/////////////////////////////////////////////////////////////////////////
//
// File:	memory_dspstak_sx2_zx2.asm
// Version:	1.01		
// Build 	1.00
// Tools:	Visual DSP 4.5
//
// dspstak sx2 zx2 User Memory Library
//
// Date:	August 06
//
// Author:	Danville Signal Processing, Inc.
//
// http://www.danvillesignal.com
//
/////////////////////////////////////////////////////////////////////////



#if defined(__ADSP21262__)
#include <def21262.h>
#include "spi_dspstak_sx.h"			
#include "flash_dspstak_sx.h"

#elif defined(__ADSP21364__)
#include <def21364.h>
#include "spi_dspstak_sx.h"			
#include "flash_dspstak_sx.h"


#elif defined(__ADSP21369__)
#include <def21369.h>
#include "spi_dspstak_sx2_zx2.h"
#include "memory_dspstak_sx2_zx2.h"

#endif


#define FLASH_READ_BUFF			10
#define EEPROM_READ_BUFF		10

// GLOBAL Flash functions
.GLOBAL _init_user_flash;				// initialization for user flash
.GLOBAL _flash_add_queue;		
.GLOBAL _flash_manager;

// GLOBAL Flash variables
.GLOBAL flash_dev_id;					// device id	
.GLOBAL flash_manf_id;					// manufacturer id

.GLOBAL flash_queue;
.GLOBAL flash_queue_head_ptr;
.GLOBAL flash_queue_tail_ptr;

.GLOBAL flash_msg_log;
.GLOBAL flash_msg_log_head_ptr;
.GLOBAL flash_msg_log_tail_ptr;


// GLOBAL eeprom functions
.GLOBAL _init_user_eeprom;
.GLOBAL _eeprom_add_queue;
.GLOBAL _eeprom_manager;

// GLOBAL eeprom variables
.GLOBAL eeprom_queue;
.GLOBAL eeprom_queue_head_ptr;
.GLOBAL eeprom_queue_tail_ptr;

.GLOBAL eeprom_msg_log;
.GLOBAL eeprom_msg_log_head_ptr;
.GLOBAL eeprom_msg_log_tail_ptr;

.GLOBAL _complete_mem_spi_transfer;


/////////////////////////////////////////////////////////////////////////
//
//	Overview and Notes
//
//	Each dspstak engine comes with non-volative memory which the user can 
//	use in their applications.  There are two memory types that  the user 
//	can access namely a flash memory space and an eeprom memory space. 
//	Do take note that not every dspstak engine will have an eeprom memory.
//	To date, only the dspstak sx base engines only have the flash memory.
//	However, the dspstak sx does have an alternative eeprom space available
//	from its' peripheral microcontroller.
//
//	Both the flash and eeprom memory devices are accessed via spi communication.
//  Thus in order to conduct commands toward these devices, the spi management
//	library works hand in hand with the memory command managers.  There are
//	certain details that the user should be aware about the available memory
//	resources from the devices and they are discussed below.  In addition 
//	the code base for the flash and eeprom devices have further notes on how
//	to access or issue commands to the specific device.
//
//	Memory Space and Boundaries
//
//	The flash memory in the dspstak engines is primarily used as the boot memory
//	device.  Danville has its' own proprietary bootloader program that allows
//	users to upload loader (ldr) files generated by ADI's Visual DSP. The uploaded
// 	program is then burned in the flash memory. Since the flash memory is shared
//	with other programs(/and data) used in running the system, it is important
//	that there is robust management in handling the 'user' memory space.  The user
//  is allocated to user the last 32 kilo bytes of the 4 Mega bit device.  
//	The library written for the user space further abstracted the memory space
//  so as to make the memory space appear to be an 8 kilo word space, where
//	each word is 32 bits. The advantage of doing so is that the SHARC DSPs have
//  an inherent 32 bit register set.  The written library has incorporated safety
//	code so that the user cannot impede on other space that is outside the 
//	assigned memory block.  For the eeprom however, the user has full access
//  of the whole memory space with one exception for a particular family.
//  The dspstak sx2 and zx2 families reserves for future use the last
//	256 bytes of the eeprom space.  This space is reserved for future use in
//	incorporating improvements in the dspstak engine model and for future
//	enhancements in the supported functionality of the engine.  One difference
//	that should be noted for the eeprom code, there is support in order for the
//  user to store different width data namely 8, 16 and 32 bit words.  It is
//  highly suggested that the user segment the eeprom memory space to organize
//	where the byte space, 16 bit and 32 bit boundaries are located.  Ofcourse,
//	this is dependent on the user application.
//
//	
//	Memory Reads and Writes
//
//	Memories are for the basic purpose of remembering data and the only thing
//	that we need it for is writing data and reading the data back.  Flash memory
//	operate in a straight forward fashion with respect to reading. Writing data
//	to flash is a different story. In order to successfully write a flash memory
//	location, it should be erased first. Flash memories operate in a fashion when
//	data are normally high, so each byte is normally read as 0xFF and then once
//	the byte is written with a different value, subsequent writes will only account
//  for the bit locations where there are still set bits.  For example, if the 
//	original byte is 0xFF, and then you write a 0xA5 and then you write write a 
//	0xAA, the result will end up with a 0xA0 value on that address.  This however
//  is not true with eeproms.  Eeproms don't need to have an intermediate
//  erase operation before a new write operation.
//
//	In addition, when executing a write (and this is true for flash and eeprom)
//	or any  modification process, there are subsequent processes involved namely: 
//		1) 	issuing a write enable command before the actual write command
//		2) 	issuing a status register read command to track if the write
//			operation is done.
//
//	Memory Protection
//
//	Both the flash and eeprom devices are protected from writes and modifications 
//	upon power up. Thus, in case that the user has to issue write commands, the 
//	first step is to issue an unprotect command.  Furthermore, these memory
//	devices have mechanisms in protecting different sections of the whole space.
//	Code is written to support this feature.
//
//	Supporting Code
//
//	As mentioned above, both the flash  and eeprom devices are controlled via 
//	spi. The code base below operates with the spi management code library written
//	by Danville Signal.  Furhter information on how the spi management works can
//	be read in the spi_dspstak_sx2_zx2 files.  There is a surrounding level of 
//	management for each of the memory devices.  The primary task of the 
//	memory device command managers (which are flash_manager and eeprom_manager) is
//	to properly feed the spi management (spi_manager).
//
//	Memory Activity Log
//
// 	There is an activity log buffer where the user can track which commands have 
//	been serviced by both the memory command manager (flash_manager or eeprom_manager)
//	and by the spi manager.  Each memory device has its' own log buffer.  The
//	flash log buffer is organized in four word boundaries and the eeprom buffer
//	has three word boundaries. The log buffer significant information as to 
//	what command has been serviced and any other significant information such
//	as accessed address and written or read data.
//	
/////////////////////////////////////////////////////////////////////////


.SECTION/DM seg_dmda;

// Flash Variables
.VAR flash_device_settings[3] =
	SPI_BAUD_5MHZ,						// SPI baud for flash
	SPI_FLASH_SS,						// slave select flag
	SPIMS | 							// Master mode (internal SPICLK) 
	SPIEN| 								// Enable SPI port 
	TIMOD1|								// transfer mode 1
	MSBF|								// send MSB first
	CPHASE|								// control CS manually
	CLKPL |
	WL8 |								// 8 bit transfer
	SENDZ; 								// send zero if transmission buffer is empty

.VAR flash_receive_buffer[FLASH_READ_BUFF];	
										// receive buffer should be atleast one word wide
					
						
.VAR flash_id_com_atmel[5]=
	SPI_DEVICE_FLASH | SPI_TR  | FL_SEND4,
	FL_RD_ID_ATMEL,							// read flash id command
	0x00,								// address three byte msb 
	0x00,								// address for manf id = x000000
	0x00;								// flash receive buffer conatining
										// manufacturer and device										
.VAR flash_id_com_stmicro[7]=
	SPI_DEVICE_FLASH | SPI_TR  | FL_SEND6,
	FL_RD_ID_STMICRO,					// read flash id command
	0x00,								// address three byte msb 
	0x00,								// address for manf id = x000000
	0x00,								//
	0x00,								// two bytes can be read from
	0x00;								// flash receive buffer conatining
										// manufacturer and device										
										
.VAR flash_wrdi[2]=
	SPI_DEVICE_FLASH ,	
	FL_WRDI	;							// write mem disable command

.VAR flash_wren[2]=
	SPI_DEVICE_FLASH | SPI_HS,	
	FL_WREN;							// write mem enable command

.VAR flash_ewsr[2]=
	SPI_DEVICE_FLASH | SPI_HS ,	
	FL_EWSR	;							// write enable status reg

.VAR flash_rdsr[3]=
	SPI_DEVICE_FLASH | SPI_TR | SPI_HS | FL_SEND2 ,	
	FL_RDSR,							// give read status reg command
	0x00;								// read from flash receive buffer

.VAR flash_wrsr[3]=
	SPI_DEVICE_FLASH | SPI_HS |FL_SEND2 ,	
	FL_WRSR,
	0x00;								// write status reg

.VAR flash_write[6]=		
	SPI_DEVICE_FLASH | FL_SEND5 | SPI_HS,	
	FL_WR_BYTE,							// write byte command
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00,								// three word address LSB
	0x00;								// byte value must be changed here
	
.VAR flash_read32[9] =		
	SPI_DEVICE_FLASH | SPI_TR | SPI_HS | FL_SEND8,	
	FL_RD_BYTE,							// read byte command
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00,								// three word address LSB
	0x00,								// extra 4 words to accomodate
	0x00,								// 32 bit user word
	0x00,
	0x00;								// byte must be read from flash receive buffer

.VAR flash_sector_erase[5] = 
	SPI_DEVICE_FLASH | FL_SEND4 | SPI_HS,	
	FL_SECTOR_ERASE,
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00;
	
	
	
.VAR flash_protect_section[5] = 
	SPI_DEVICE_FLASH | FL_SEND4 | SPI_HS,	
	FL_PROTECT_SECTION,
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00;

.VAR flash_unprotect_section[5] = 
	SPI_DEVICE_FLASH | FL_SEND4 | SPI_HS,	
	FL_UNPROTECT_SECTION,
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00;
	
.VAR flash_read_protection_reg[6] = 
	SPI_DEVICE_FLASH | FL_SEND5 | SPI_HS | SPI_TR,	
	FL_RD_PROT_REG,
	0x07,								// default to smallest user address
	0x80,								// three word address
	0x00,
	0x00;								// last word necessary for the read 

		
	
.VAR flash_dev_id;						// holds the device id
.VAR flash_manf_id;						// holds the manufacture id
.VAR flash_identification;				

.VAR flash_queue[FL_QUEUE_SIZE];		// queue of flash commands
.VAR flash_queue_head_ptr= flash_queue;	// initialize head and tail pointers to start	
.VAR flash_queue_tail_ptr= flash_queue; // queue rule add at head, grab at tail

.VAR flash_msg_log[FL_MSG_LOG_SIZE];		// user can look at this and base decisions
.VAR flash_msg_log_head_ptr= flash_msg_log;	// this data struct keeps track of all
.VAR flash_msg_log_tail_ptr= flash_msg_log;	// commands sent executed already

.VAR flash_spi_service_state = 0;		// data that keeps states executed
.VAR flash_invalid_address = 0;			//

.VAR flash_command;						// holds flash command
.VAR flash_address;						// address
.VAR flash_data32;						// data
.VAR flash_data32_temp;					// scratch pad for data word
.VAR flash_shift;						// used in converting 8 to 32 vice versa

.VAR flash_high_byte_addr =0x07;		// true for all user flash space
.VAR flash_mid_byte_addr;	
.VAR flash_low_byte_addr;				
.VAR flash_write_cntr;					// used when issuing writes

.VAR flash_sector_command_type;			// declare if command is sector based
.VAR flash_sector_command;				
						
.VAR flash_sector_addr;					// sector location, only used in sector commands
.VAR flash_source_addr;					// used in sector writing
.VAR flash_destination_addr;			// used in sector reading

.VAR flash_sector_ptr;					// moving pointer in sector operations
.VAR flash_sector_transfer_size;		// amount of word transfers in sector operations
.VAR flash_sector_transfer_cntr;		// amount of word transfers in sector operations


.VAR flash_temporary_storage[5];


// eeprom variables
.VAR eeprom_device_settings[3] =
	SPI_BAUD_1MHZ,						// SPI baud for eeprom
	SPI_EE_SS,							// slave select flag
	SPIMS | 							// Master mode (internal SPICLK) 
	SPIEN| 								// Enable SPI port 
	TIMOD1|								// transfer mode 1
	MSBF|								// send MSB first
	CPHASE|								// control CS manually
	CLKPL |
	WL8 |								// 8 bit transfer
	SENDZ; 								// send zero if transmission buffer is empty

.VAR eeprom_receive_buffer[EEPROM_READ_BUFF];

.VAR eeprom_spi_service_state;
	
.VAR eeprom_wrdi[2]=
	SPI_DEVICE_EE  | SPI_HS,	
	EE_WRDI	;							// eeprom write disable command

.VAR eeprom_wren[2]=
	SPI_DEVICE_EE | SPI_HS ,	
	EE_WREN	;							// eeprom write enable command

.VAR eeprom_rdsr[3]=
	SPI_DEVICE_EE | SPI_TR | SPI_HS | EE_SEND2,	
	EE_RDSR,							// read status register command
	0x00;								// send extra byte for read back

.VAR eeprom_wrsr[3]=
	SPI_DEVICE_EE |  SPI_HS | EE_SEND2,	
	EE_WRSR,							// write status register command
	0x00;								// new status register value goes here
		
.VAR eeprom_read_data[8]=
	SPI_DEVICE_EE | SPI_TR | SPI_HS | EE_SEND7,	
	EE_READ,							// read data command
	0x00,								// ms byte address
	0x00,								// ls byte address	
	0x00,								//	four words to grant provision in  
	0x00,								//	reading a byte, 16 bit word or 32 bit word
	0x00,								//
	0x00;								//


.VAR eeprom_write_data[8]=
	SPI_DEVICE_EE | SPI_TR | SPI_HS | EE_SEND7,	
	EE_WRITE,							// write data command
	0x00,								// ms byte address
	0x00,								// ls byte address	
	0x00,								// four words to grant provision in  
	0x00,								// reading a byte, 16 bit word or 32 bit word
	0x00,								//
	0x00;								//
	

	
.VAR eeprom_queue[EE_QUEUE_SIZE];
.VAR eeprom_queue_head_ptr = eeprom_queue; 
.VAR eeprom_queue_tail_ptr = eeprom_queue; 
			
.VAR eeprom_msg_log[EE_MSG_LOG_SIZE];
.VAR eeprom_msg_log_head_ptr = eeprom_msg_log;
.VAR eeprom_msg_log_tail_ptr = eeprom_msg_log;


.VAR eeprom_command;
.VAR eeprom_addr;
.VAR eeprom_data;

.VAR eeprom_write_type;					// tell whether write operation is for status reg (0)
										// or data (1)
.VAR eeprom_data_type;					// utilize m5, m6 and m7 rule to signify
										// 8 bit (0), 16 bit (1), and 32 bit (-1)

.VAR eeprom_temporary_storage[5];																				
																				
										
.SECTION/PM seg_pmco;


// -- -- -- F L A S H    C O D E     B A S E     S T A R T    -- -- -- -- -- //


/////////////////////////////////////////////////////////////////////////
//
// 	USAGE of Flash commands
//
//		To read flash status register:
//					r4 = FL_CMD_STATUS;
//					CALL _flash_add_queue;
//
//		To allow flash read only:
//					r4 = FL_CMD_PROTECT;
//					CALL _flash_add_queue;
//
//		To allow flash read/write:
//					r4 = FL_CMD_UNPROTECT;
//					CALL _flash_add_queue;
//
//		To erase a sector:
//					r4 = FL_CMD_ERASE_SECTOR;
//					r8 = FL_SECTOR4;  	(users have sectors 0 to 7)				
//					CALL _flash_add_queue;
//
//		To write a 32 bit word:
//					r4 = FL_CMD_WRITE32;
//					r8 = 0x1009		  	(address available 0x0000 to 0x1FFF)
//					r12 = 0xABCD1234; 	(32 bit word data)
//					CALL _flash_add_queue;
//
//		To read a 32 bit word
//					r4 = FL_CMD_READ32
//					r8 = 0x874;		 	(address available 0x0000 to 0x1FFF)
//					CALL _flash_add_queue;
//
//		To write a flash sector
//			This will transfer all contents of dsp_side_variable to sector3.
//			User has to make sure that sector 3 previously erased.
//			Amount of transfer is propotional to size of dsp_side_variable
//					r4 = FL_CMD_WRITE_SECTOR;	
//					r8 = FL_SECTOR3;		(users have sector 0 to 7)
//					r12 = dsp_variable;  
//					r14 = Transfer Length;
//					CALL _flash_add_queue;
//		
//		To read a flash sector
//			This will transfer all contents of sector 4 to dsp_side_variable.
//			Amount of transfer is propotional to size of dsp_side_variable
//					r4 = FL_CMD_READ_SECTOR;	
//					r8 =  FL_SECTOR4;		(users have sector 0 to 7)
//					r12 = dsp_variable;  
//					r14 = Transfer Length;
//					CALL _flash_add_queue;
//		** Transfer Length: Since a user sector is 1 K word.  This additional information
//							will dictate the actual number of words to be transferred. 
//							Maximum transfer length is 1024 
//		
//		The following three flash commands are only available for the Atmel AT26F004
//		spi flash part.These three commands have something to do the protection and 
//		unprotection of the user flash memory space.  The protect and unprotect memory 
//		command found above are called to manage the protection for the whole user 
//		flash memory range.  In the Atmel documentation, the user memory space has 
//		an internal protection division of three parts. With respect to this library
//		we refer to these divisions into sections.  Sections 1 and 2 are both of 8 kB
//		size and Section 3 is a 16 k byte.  The user therefore can custom protect the
//		user flash memory space.  In addition for every special section there is a set
//		of registers that determine whether this section is protected or not.
//
//		The division for the three sections are
//	
//		ATMEL_SECTION1	section from 0x78000 - 0x79FFF
//		ATMEL_SECTION2	section from 0x7A000 - 0x7BFFF
//		ATMEL_SECTION3	section from 0x7C000 - 0x7FFFF
//
//		To protect user section 1
//					r4 = FL_CMD_PROTECT_SECTION;
//					r8 = FL_ATMEL_SECTION1;
//					CALL _flash_add_queue;
//
//		To unprotect user section 3	
//					r4 = FL_CMD_UNPROTECT_SECTION;
//					r8 = FL_ATMEL_SECTION3;
//					CALL _flash_add_queue;
//
//      To read the protection status register of section 2
//					r4 = FL_CMD_READ_PROTECT_REG;
//					r8 = FL_ATMEL_SECTION2;
//					CALL _flash_add_queue;
//
//	Keeping Track of Serviced Flash Commands
//
//		The user can use the variable flash_msg_log to view and to keep track 
//		which commands has been successfully executed as well as data read back
//		or written to the flash memory.  Using the flash_msg_log_tail_ptr variable
//		as the DAG pointer, the data structure flash_msg_log is arranged in words 
//		of four with the sequence of 
//					1) issued command
//					2) address/sector number related to command (sector for sector_erase)
//					3) data / addr word (32 bit) related to command    (only works for write and read)
//					4) data word (only significant in sector operations)
//
//		Commands FL_CMD_STATUS,	r4 = FL_CMD_PROTECT, and FL_CMD_UNPROTECT
//		does not have addresses or data related to them but constants are 
//		written to flash_msg_log in order to maintain the four word boundary
//
//	User Flash Memory Space
//
//		The following is a table on how the user flash memory space
//		is organized.  Do take note that the nomenclature for the sections,
//		are only applicable to the ATMEL AT26F004.  In addition, the AT26F004
//		has a increased granularity level of memory protection and the 
//		protection granularity is based on the sections and each section
//		has associated protection status registers.  
//
//		Section		Sectors	 	Absolute Address Range	User Address Range
//		   1	   	0			0x78000 - 0x78FFF		0x000 - 0x3FF
//		   1	   	1			0x79000 - 0x79FFF		0x400 - 0x7FF
//		   2	   	2			0x7A000 - 0x7AFFF		0x800 - 0xBFF
//		   2	   	3			0x7B000 - 0x7BFFF		0xC00 - 0xFFF
//		   3	   	4			0x7C000 - 0x7CFFF		0x1000 - 0x13FF
//		   3	   	5			0x7D000 - 0x7DFFF		0x1400 - 0x17FF
//		   3	   	6			0x7E000 - 0x7EFFF		0x1800 - 0x1BFF
//		   3	   	7			0x7F000 - 0x7FFFF		0x1C00 - 0x1FFF
//
/////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//
//	_init_user_flash
//
//	Notes:
//			Declares the flash as a spi device according to the danville
//			SPI protocol.  Declared as device 1.  Also read identification
// 			numbers from flash device. Must be called during initialization purposes.
//
//	Written by Danville Signal Processing
//
//	Date:					10 May 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			NONE
//			
//	Modified register:  	r4, r8, r12
// 
//////////////////////////////////////////////////////////////////////////////////
_init_user_flash:

	r4 = SPI_DEVICE_FLASH;				// SPI Device Number	
	r8 =  flash_device_settings;		// SPI device parameters
	r12 = flash_receive_buffer;			// Buffer used for each individual byte 
	
	CALL _init_spi_device;				// declare device parameters for flash in
										// spi protocol
	CALL _read_flash_ids;				// ids of flash are read
	
	RTS;
_init_user_flash.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_read_flash_ids
//
//	Notes:
//			Reads the flash memory's id numbers and returns the manufacturer
//			and device id's. Essential in initialization purposes.
//
//			This subroutine is particulary significant when the user wants to 
//			determine which device is populated in the dspstak engine. Different
//			devices have different commands, and features but majority of the 
//			basic functions are much common than different.  Once the user
//			is definite as to what type of device  is present in the system,
//			the user should properly change the definition of 
//			FL_DECLARED_DEVICE in the memory_dspstak_sx2_zx2.h
//			
//
//	Written by Danville Signal Processing
//
//	Date:					16 June 06
//
//	Calling parameters: 	NONE
//
// 	Return value:			DM(flash_manf_id)
//							DM(flash_dev_id)
//							r0 = 	1 	Valid Flash Device supported
//									0	Invalid Flash Device supported
//			
//	Modified register:  	r0, r4, r8
//
//////////////////////////////////////////////////////////////////////////////////

_read_flash_ids:

scan_atmel_flash:
	r4 = flash_id_com_atmel;			// send flash id command to scan an atmel device
	CALL _spi_add_queue;
	CALL _complete_mem_spi_transfer;
	
	r4 = DM(flash_receive_buffer + 2);	// at these locations contains
	DM(flash_manf_id) = r4;				// the data read back aligned
										// to the manufacturer and device ids
										
	r8 = FL_ATMEL_MANF_ID;				// check whether read manufacturer id						
	COMP(r4, r8);						// matches the atmel id
	IF NE JUMP scan_stmicro_flash;
										
	r4 = DM(flash_receive_buffer + 3);	
	DM(flash_dev_id) = r4;				
	
	r4 = FL_ATMEL_AT26F004;				// Save variable with internal library value
	DM(flash_identification) = r4;		
											
	r0 = m6; 							// r0 = Valid Device	
	JUMP _read_flash_ids_exit;
	
scan_stmicro_flash:	

	r4 = flash_id_com_stmicro;			// send flash id command to scan a stmicro device
	CALL _spi_add_queue;
	CALL _complete_mem_spi_transfer;
	
	r4 = DM(flash_receive_buffer + 5);	// at these locations contains
	DM(flash_manf_id) = r4;				// the data read back aligned
										// to the manufacturer and device ids
	
	r8 = FL_STMICRO_MANF_ID;			// check whether read manufacturer id						
	COMP(r4, r8);						// matches the stmicro id
	IF NE JUMP scan_future_flash_devices;
																					
	r4 = DM(flash_receive_buffer + 6);	
	DM(flash_dev_id) = r4;	
	
	r4 = FL_STMICRO_25VF040;			// Save variable with internal library value
	DM(flash_identification) = r4;
	r0 = m6; 							// r0 = Valid Device
					
	JUMP _read_flash_ids_exit;			

scan_future_flash_devices:

// Spot where future flash devices will be supported.
scan_unsupported_flash_device:
	DM(flash_manf_id) 	= m5;			// Clear this variables
	DM(flash_dev_id) 	= m5;	
	r0 = m5;							// r0 = Invalid Device
	
	r4 = FL_INVALID_DEVICE;				
	DM(flash_identification) = r4;		// Declare an invalid/ unsupported device
	RTS;
	
_read_flash_ids_exit:
	
	r4 = FL_DECLARED_DEVICE;			// Compare declared flash device
	r8 = DM(flash_identification);		// to what is detected
	COMP(r4, r8);						// if there is a match
	IF EQ RTS;							// device is fully supported					
	
	r4 = FL_MISMATCH;					// If there is a mismatch, 
	DM(flash_identification) = r4;		// variable is overwritten 
	r0 = m5;							// and r0 is cleared
		
	RTS;
	
_read_flash_ids.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_complete_mem_spi_transfer
//
//	Notes:
//			Forces a completion of spi transfers.  Basically flushes spi queue. 
//			This is good for static device testing and initialization purposes.
//			
//	Written by Danville Signal Processing
//
//	Date:					28 May 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			NONE
//			
//	Modified register:  	r14, r15
//
//////////////////////////////////////////////////////////////////////////////////

_complete_mem_spi_transfer:

force_mem_spi_loop:
	CALL _spi_manager;		
	r15 = DM(_spi_queue_head_ptr);		// check if spi queue is flushed	
	r14 = DM(_spi_queue_tail_ptr);		// it is flushed if head and tail are equal
	COMP(r14, r15);
	IF NE JUMP force_mem_spi_loop;
	
	RTS;	
	
_complete_mem_spi_transfer.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_flash_add_queue
//
//	Notes:
//			Adds a flash memory based command to the queue.  The queue is serviced
//			by calling _flash_manager.  
//
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	r4 = flash command
//							r8 = address/ sector number if necessary
//							r12 = addr / data if necessary
//							r14 = transfer length data (only for sector operations)
//			
//	Command Types
//		1. Flash read status 			r4 needed
//		2. 32 bit word read/ write 		r4, r8 , r12 needed
//		3. Sector erase					r4, and r8 needed
//		4. Protect / Unprotect Memory	r4 needed
//		5. Read/ Write Sector 			r4, r8 ,r12, r14 needed
//
// 	Return value:			NONE
//			
//	Modified register:  b1, i1, l1
//
//////////////////////////////////////////////////////////////////////////////////

_flash_add_queue:

	b1 = flash_queue;					// point to flash queue
	i1 = DM(flash_queue_tail_ptr);		// new commands are filled at the tail end
	l1 = FL_QUEUE_SIZE;			
	
	DM(i1, m6) = r4;					// command, address, data 
	DM(i1, m6) = r8;					// parameters dependent on command
	DM(i1, m6) = r12;					// four word boundary is maintained
	DM(i1, m6) = r14;					// for all commands
	
	DM(flash_queue_tail_ptr) = i1;		// update tail ptr
	
	RTS;
_flash_add_queue.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_flash_manager
//
//	Notes:
//			Manages the flash command queue.  Checks if there are any flash commands
// 			to be serviced and branches to a specific command.  The flash manager 
//			should be coupled with spi manager.
//			
//	Flash queue notes:
//			The Flash queue is serviced in four word boundaries for the reason
//			to accomodate the most complex flash based commands.  The greatest number
//			of parameters allocated to any flash command is four.
//
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			r0 	= '0' flash queue empty 
//								= non zero value saying queue not empty
//
//							
//	Modified register:  	r0, r14, r15, b1, i1, l1, m1, i8, m8
//
//////////////////////////////////////////////////////////////////////////////////

_flash_manager:

	r0 = 0;								// return value in case flash queue is empty
	r14 = DM(flash_queue_tail_ptr);		// check if head and tail are equal if not
	r15 = DM(flash_queue_head_ptr);		// time to service flash commands
	COMP(r14, r15);
	IF EQ RTS;							// return 0 if empty

	r0 = 1;								// ensure return value is non zero
										// subsequent handlers should also return r0 = non '0'
										
	b1 = flash_queue;					// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;
	
	r14 = DM(i1, m5);					// check if command is valid
	r15 = FL_INVALID_CMD;				// if non valid
	COMP(r14, r15);
	IF GE JUMP flash_invalid_command;	
	
	m8 = r14;							// get command number
	i8 = flash_manager_branch;	
	JUMP(m8, i8);						// and branch to command handler
																									
flash_manager_branch:					// get command type and go to 
										// command handler
	
#if	FL_DECLARED_DEVICE==FL_STMICRO_25VF040

	JUMP _read_flash_status;	
	JUMP _protect_flash;
	JUMP _unprotect_flash;
	JUMP _erase_flash_sector;
	JUMP _write32_flash;
	JUMP _read32_flash;
	JUMP _write_flash_sector;
	JUMP _read_flash_sector;
	
#elif FL_DECLARED_DEVICE==FL_ATMEL_AT26F004									

	JUMP _read_flash_status;	
	JUMP _protect_flash;
	JUMP _unprotect_flash;
	JUMP _erase_flash_sector;
	JUMP _write32_flash;
	JUMP _read32_flash;
	JUMP _write_flash_sector;
	JUMP _read_flash_sector;
	JUMP _protect_flash_section;
	JUMP _unprotect_flash_section;
	JUMP _read_protection_register;
	
#endif
	
flash_invalid_command:					// if command is invalid skip to the next
										// command (skip by four)
    i1 = DM(flash_queue_head_ptr);
	m1 = FL_QUEUE_SKIP;					//modify the tail pointer by four to satisfy
	MODIFY(i1 , m1);					// flash queue boundaries		
	DM(flash_queue_head_ptr) = i1;		
											
	RTS;
_flash_manager.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_read_flash_status
//
//	Notes:		Adds a spi command for a read flash status and then upon completion
//				it logs onto the flash msg log structure the flash status byte
//		
//	Written by Danville Signal Processing
//
//	Date:					31 May 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ flash_msg_log	(four words)
//								-->	FL_CMD_STATUS
//								--> Actual Flash Status Register
//								--> 1
//								--> 1
//														
//	Modified register:  	r4, r8, r12, r14, ustat1
//
//////////////////////////////////////////////////////////////////////////////////
_read_flash_status:
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP _read_flash_status_wait;			// if sent check if particular command is done
	
	r4 = flash_rdsr;							// add read flash status spi command
	CALL _spi_add_queue;
	
	r14 = FL_SPI_WAIT;							// change flash spi service state
	DM(flash_spi_service_state) = r14;

	DM(flash_receive_buffer) = m6;				// this is needed to be set for spi handshake
	
_read_flash_status_wait:	

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
//	DM(flash_receive_buffer) = m6;				// Re arm for next spi command, avoid stall
	
	r4 = FL_CMD_STATUS;							// save flash command
	r8 = DM(flash_receive_buffer + 2);			// fourth word significant
	r12 = m6;									// get actual Flash Status byte
	r14 = m6;									
	
	JUMP _exit_flash_command;					// save to flash msg log and advance queue
	
_read_flash_status.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_write_flash_status
//
//	Notes:		State handler for writing the flash status register.  This involves
//				two steps: issuing enable write status reg and issuing a write 
//				status register spi packet.
//
//	Written by Danville Signal Processing
//
//	Date:					31 May 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ flash_msg_log	(four words)
//								-->	FL_CMD_PROTECT or UNPROTECT; // save flash command
//								--> 1
//								-->	1
//								--> 1
//														
//	Modified register:  	r4, r8, r12, r14, ustat1
//
//////////////////////////////////////////////////////////////////////////////////
_write_flash_status:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP write_flash_status_wait;			// and waiting for it to complete

write_flash_status_step1:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP1;				// check if step one is done
	IF TF JUMP write_flash_status_step2;		// else advance to next step

	r4 = flash_ewsr;							// send a enable write status register command
	CALL _spi_add_queue;

	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP1;	// Say that command handler will wait and has
	DM(flash_spi_service_state) = ustat1;		// issued step 1 already
	
	DM(flash_receive_buffer) = m6;				// the enable write status register
												// must be completely finished before
	RTS;										// issuing the write status register command
		
write_flash_status_step2:
												
	r4 = flash_wrsr;							// issue write status register command
	CALL _spi_add_queue;						
	
	ustat1 = DM(flash_spi_service_state);		
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP2;	// Say that command handler will wait and has
	DM(flash_spi_service_state) = ustat1;		// issued step 2 
		
	DM(flash_receive_buffer) = m6;				// Set this word to allow spi handshake
	
	RTS;
	
write_flash_status_wait:
		
	r14 = DM(flash_receive_buffer);				// if first word of flash receive buffer
	r14 = pass r14;								// is cleared this means
	IF NE RTS;									// that spi service is done
	
//	DM(flash_receive_buffer) = m6;				// set for next spi based command
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// disable flash wait after good handshake
	DM(flash_spi_service_state) = ustat1;		
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP2;				// check if second spi command is sent already
	IF NOT TF JUMP write_flash_status_step2;			
		
write_flash_status_exit:	
	
	r4 = DM(flash_command);						// save flash command
	r8 = m6;									// this could be changed
	r12 = m6;									// but ones are just okay
	r14 = m6;
	
	JUMP _exit_flash_command;					// saves into flash_msg_log
												// and restarts flash handler states
_write_flash_status.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_protect_flash
//				
//	Notes:		This subroutine once executed locks the user flash memory space to
//				be read only memory.
//
//				There may be different features associated with different flash
//				chips.  As of July 2006, there are two (2) types of flash devices
//				supported by the dspstak engine	namely: STMICRO 25VF040 and the
//				ATMEL AT26F004.  The process with respect to protecting and 
//				unprotecting the user flash memory space is different between 
//				devices.  Thus, there is a separate handler for each device and
//				they are branched according to the definition of FL_DECLARED_DEVICE	
//				in the header file		
//				
//				STMICRO 25VF040 Protection
//				Set the BPL bits on the flash status register.  Setting this bits
//				allow read only access to the flash.  The spi transfers are done by
//				_write_flash_status.  
//
//				ATMEL AT26F004 Protection
//				There are three 'sections' that cover the user flash space and each
//				can be customly protected and therefore there are three commands to 
//				protecting each of the sections	one by one.  
//
//	Written by Danville Signal Processing
//
//	Date:					15 July 06
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ flash_msg_log	(four words)
//								-->	FL_CMD_PROTECT;	// save flash command
//								--> 1
//								-->	1
//								--> 1
//														
//	Modified register:  	r4, r8, r12, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////

_protect_flash:

#if	FL_DECLARED_DEVICE==FL_STMICRO_25VF040
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// the init state is changing the wrsr packet
	IF TF JUMP _write_flash_status;				// if done go to other handler

	ustat1 = DM(flash_wrsr + 2);
	BIT SET ustat1 FL_BP0_BIT	| FL_BP1_BIT;	// make sure that status register is set out
	DM(flash_wrsr + 2) = ustat1;				// make BPLx bits one to make flash read only
		
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT;					// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		
	
	ustat1  = FL_CMD_PROTECT;					// will be useful in logging 
	DM(flash_command) = ustat1;

	JUMP _write_flash_status;					// this will send the commands 
	
	
#elif FL_DECLARED_DEVICE==FL_ATMEL_AT26F004	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if handler is suppose to go the WAIT condition
	IF TF JUMP protect_flash_wait;				

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// the init state of issuing a write enable is issued already
	IF TF JUMP protect_flash_step_1;			// if so go to next step 

	// The write enable command should be issued prior to protecting sectors
	r4 = flash_wren;					
	CALL _spi_add_queue;						// Issue write enable command
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
			
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT | FL_SPI_WAIT;	// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		
	
	JUMP protect_flash_wait;

protect_flash_step_1:	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP1;				// check if step 1 is issued already
	IF TF JUMP protect_flash_step_2;			// if so go to next step
		
	r15 = FL_ATMEL_SECTION1;					// protect Atmel section 1
	DM(flash_protect_section + 3) = r15;
	r4 = flash_protect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP1 | FL_SPI_WAIT;	// step 1 and wait flag is set
	BIT CLR ustat1 FL_SPI_INIT;					//  clear the init flag to issue another write enable
	DM(flash_spi_service_state) = ustat1;
	
	JUMP protect_flash_wait;
	
protect_flash_step_2:
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP2;				// check if step 2 is issued already
	IF TF JUMP protect_flash_step_3;			// if so go to next step
	
	r15 = FL_ATMEL_SECTION2;					// protect Atmel section 2
	DM(flash_protect_section + 3) = r15;
	r4 = flash_protect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP2 | FL_SPI_WAIT;	// step 2 and wait flag is set
	BIT CLR ustat1 FL_SPI_INIT;					// clear the init flag to issue another write enable
	DM(flash_spi_service_state) = ustat1;
	
	JUMP protect_flash_wait;
	
protect_flash_step_3:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP3;				// check if step 3 is issued
	IF TF JUMP protect_flash_wait;				

	r15 = FL_ATMEL_SECTION3;					// protect Atmel section 3
	DM(flash_protect_section + 3) = r15;
	r4 = flash_protect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP3 | FL_SPI_WAIT;	// the step 3 and wait flag is set
	DM(flash_spi_service_state) = ustat1;
	
	JUMP protect_flash_wait;
	
protect_flash_wait_status:

	r4 = flash_rdsr;							// issue a read status register command
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP4 ;	// ask handler to wait and track the status register
	DM(flash_spi_service_state) = ustat1;
	
		
protect_flash_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// clear the wait state flag
	DM(flash_spi_service_state) = ustat1;
	
	BIT TST ustat1 FL_SPI_STEP4;				// STEP 4 is tracking the flash status register
	IF NOT TF JUMP protect_flash_wait_status;	// if not set reading status register command is not issued yet
	IF TF JUMP protect_flash_wait_status_test;	//  the status register should be tested if flash is busy
		
protect_flash_wait_status_test:												

	ustat1 = DM(flash_receive_buffer + 2);		// read status register
	BIT TST ustat1 FL_BUSY_BIT;
	IF TF JUMP protect_flash_wait_status;
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_STEP4;				// the step of reading the the status register is done and flash is ready
	DM(flash_spi_service_state) = ustat1;
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP3;				// check if the last step (step 3) which is protecting section 3
	IF NOT TF JUMP _protect_flash;				// if not yet done go to start to do 
												// other steps
protect_flash_exit:

	r4 = FL_CMD_PROTECT;						// logging purposes
	r8 =  m6;									// log that the whole user flash memory  space is protected
	r12 = m6;
	r14 = m6;
	
	JUMP _exit_flash_command;					// _exit_flash_command routine


#endif	
	
_protect_flash.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_unprotect_flash
//
//
//	Notes:		This subroutine once executed unlocks the user flash memory 
//				space to allow write and modification processes.
//
//				There may be different features associated with different flash
//				chips.  As of July 2006, there are two (2) types of flash devices
//				supported by the dspstak engine	namely: STMICRO 25VF040 and the
//				ATMEL AT26F004.  The process with respect to protecting and 
//				unprotecting the user flash memory space is different between 
//				devices.  Thus, there is a separate handler for each device and
//				they are branched according to the definition of FL_DECLARED_DEVICE	
//				in the header file		
//				
//				STMICRO 25VF040 Protection
//				Clears the BPL bits on the flash status register.  Clearing these bits
//				allows write  access to the flash.  The spi transfers are done by
//				_write_flash_status.  
//
//				ATMEL AT26F004 Protection
//				There are three 'sections' that cover the user flash space and each
//				can be customly protected and therefore there are three commands to 
//				unprotecting each of the sections	one by one.  
//	
//	Written by Danville Signal Processing
//
//	Date:					15 July 06
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ flash_msg_log	(four word)
//								-->	FL_CMD_UNPROTECT;				// save flash command
//								--> 1
//								-->	1
//								--> 1
//														
//	Modified register:  	ustat1
//
//////////////////////////////////////////////////////////////////////////////////
_unprotect_flash:

#if	FL_DECLARED_DEVICE==FL_STMICRO_25VF040

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// check if initial state in this case
	IF TF JUMP _write_flash_status;				// changing wrsr packet is done

	ustat1 = DM(flash_wrsr + 2);
	BIT CLR ustat1 FL_BP0_BIT	| FL_BP1_BIT;	// make sure that status register is zeroed out
	DM(flash_wrsr + 2) = ustat1;				// make BPLx bits zero to access flash
		
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT;					// Say that this state is done
	DM(flash_spi_service_state) = ustat1;		// prevent from crossing here again

	ustat1  = FL_CMD_UNPROTECT;					// for logging purposes
	DM(flash_command) = ustat1;
		
	JUMP _write_flash_status;					// this will execute the spi transfers
	
	
#elif FL_DECLARED_DEVICE==FL_ATMEL_AT26F004	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if the WAIT flag is set
	IF TF JUMP unprotect_flash_wait;			// if so go to the wait handler

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// the init state is issuing a write enable command
	IF TF JUMP unprotect_flash_step_1;			// if set go to next step

	// The write enable command should be issued prior to protecting sectors
	r4 = flash_wren;					
	CALL _spi_add_queue;						// Issue write enable command
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
			
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT | FL_SPI_WAIT;	// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		
	
	JUMP unprotect_flash_wait;

unprotect_flash_step_1:	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP1;				// step 1 is protecting atmel section 1
	IF TF JUMP unprotect_flash_step_2;			// if set, step 1 is done, go to next step

	r15 = FL_ATMEL_SECTION1;					// protect atmel section1
	DM(flash_unprotect_section + 3) = r15;
	r4 = flash_unprotect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP1 | FL_SPI_WAIT;	// the step 1 and wait state is set
	BIT CLR ustat1 FL_SPI_INIT;					// clear init flag in order to issue another write enable
	DM(flash_spi_service_state) = ustat1;
	
	JUMP unprotect_flash_wait;
	
unprotect_flash_step_2:
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP2;				// step 2 is protecting atmel section 2
	IF TF JUMP unprotect_flash_step_3;			// if set, step 2 is done, go to next step

	r15 = FL_ATMEL_SECTION2;					// protect atmel section 2
	DM(flash_unprotect_section + 3) = r15;
	r4 = flash_unprotect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP2 | FL_SPI_WAIT;	// step 2 and wait state is set
	BIT CLR ustat1 FL_SPI_INIT;					// clear this flag in order to issue another write enable
	DM(flash_spi_service_state) = ustat1;
	
	JUMP unprotect_flash_wait;
	
unprotect_flash_step_3:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP3;				// step 3 is protecting atmel section 3
	IF TF JUMP unprotect_flash_wait;			// sf set, step 3 is done, go to next step

	r15 = FL_ATMEL_SECTION3;					// protect atmel section 3
	DM(flash_unprotect_section + 3) = r15;
	r4 = flash_unprotect_section;					
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP3 | FL_SPI_WAIT;	// set step 3 and wait flag
	DM(flash_spi_service_state) = ustat1;
	
	JUMP unprotect_flash_wait;
	
unprotect_flash_wait_status:

	r4 = flash_rdsr;							// issue a read status register command
	CALL _spi_add_queue;	
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP4 ;	// ask handler to wait and track the status register
	DM(flash_spi_service_state) = ustat1;
	
unprotect_flash_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// the init state is changing the wrsr packet
	DM(flash_spi_service_state) = ustat1;
	
	BIT TST ustat1 FL_SPI_STEP4;				// STEP 4 is tracking the flash status register
	IF NOT TF JUMP unprotect_flash_wait_status;	// if not set reading status register command is not issued yet
	IF TF JUMP unprotect_flash_wait_status_test;//  the status register should be tested if flash is busy
		
unprotect_flash_wait_status_test:												

	ustat1 = DM(flash_receive_buffer + 2);		// get status register
	BIT TST ustat1 FL_BUSY_BIT;					// check if flash is still busy
	IF TF JUMP unprotect_flash_wait_status;
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_STEP4;				// the step of reading the the status register is done and flash is ready
	DM(flash_spi_service_state) = ustat1;
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP3;				// check if the last step (step 3) is done
	IF NOT TF JUMP _unprotect_flash;			// if not yet done go to start to do 


unprotect_flash_exit:

	DM(flash_spi_service_state)  = m5;			// clear variable tracking states

	r4 = FL_CMD_UNPROTECT;						// logging purposes
	r8 =  m6;									// log that the whole user flash memory  space is protected
	r12 = m6;
	r14 = m6;
	
	JUMP _exit_flash_command;					// _exit_flash_command routine


#endif	


_unprotect_flash.end:

///////////////////////////////////////////////////////////////////////////////////
//
//	_erase_flash_sector
//
//	Notes:		Issues three spi commands: 
//					write enable flash
//					erase sector
//					read status reg <-- checks busy bit
//				When erasing a sector, the user erases 1 k words (32 bit width)
//				This routine also filters invalid sector numbers.
//		
//	Written by Danville Signal Processing
//
//	Date:					31 May 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ flash_msg_log	(four words)
//								-->	FL_CMD_ERASE_SECTOR;	// save flash command
//								--> SECTORx or 0  (if zero sector number invalid)
//								-->	1
//								--> 1
//														
//	Modified register:  	r4, r8, r12, r14, r15, ustat1, bi,i1,l1
//
//////////////////////////////////////////////////////////////////////////////////

_erase_flash_sector:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP erase_flash_sector_wait;			// if sent check if spi is done
												
erase_flash_sector_step1:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1  FL_SPI_STEP1;				// check if first step is issued
	IF TF JUMP erase_flash_sector_step2;		// if sent go to next step
		
	r4 = flash_wren;							// enable writen flash command
	CALL _spi_add_queue;						

	DM(flash_receive_buffer) = m6;				// Necessary for spi handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP1;	// setting state bits
	DM(flash_spi_service_state) = ustat1;
	
	RTS;

erase_flash_sector_step2:	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1  FL_SPI_STEP2;				// check if step 2 is completed
	IF TF JUMP erase_flash_sector_step3;		// if set go to next step
		
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);				// and the sector number
	l1 = FL_QUEUE_SIZE;
	
	DM(flash_sector_erase + 3) = m5;			// clear the byte that dictates sector location
												// user will know if in flash msg log
												// when clear sector location is invalid
	
	r4 = DM(m6,i1);								// making sure that we don't erase
	r14  = FL_SECTOR0;							// a sector not in the user memory space
	COMP(r4, r14);
	IF LT JUMP erase_flash_sector_exit;
		
	r14  = FL_SECTOR7;							// the user 'sector' boundary is in between
	COMP(r4, r14);								// sector 0 and 7 anything outside this will
	IF GT JUMP erase_flash_sector_exit;			// potentially corrupt non-user memory locations
	
// sector number is valid if it crosses 
	
	DM(flash_sector_erase + 3) = r4 ;			// declare sector
		
	r4 = flash_sector_erase;					// issue spi command to erase
	CALL _spi_add_queue;						// a sector
	
	DM(flash_receive_buffer) = m6;				// Necessary for spi handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP2;	// setting state bits
	DM(flash_spi_service_state) = ustat1;
	
	RTS;
	
erase_flash_sector_step3:						// step three is tracking status reg if still busy
erase_flash_sector_status:
	
	r4 = flash_rdsr;							// add spi command
	CALL _spi_add_queue;						// status reg tells if busy erasing or not			
												// ! reading flash is faster than writing
		
	DM(flash_receive_buffer) = m6;				// Necessary for spi handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP3;	// setting state bits
	DM(flash_spi_service_state) = ustat1;
	
	RTS; 
	
erase_flash_sector_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands

	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT ;				// clear this to go to other states
	DM(flash_spi_service_state) = ustat1;

	ustat1 = DM(flash_spi_service_state);
	
	BIT TST ustat1 FL_SPI_STEP2; 				// check if this state is done
	IF NOT TF JUMP erase_flash_sector_step2;
	
	BIT TST ustat1 FL_SPI_STEP3; 				// step 3 tells is the read status reg
	IF TF JUMP erase_flash_busy_test;			// test if flash is busy
	
	IF NOT TF JUMP erase_flash_sector_step3;
		
erase_flash_busy_test:	
	
	ustat1 = DM(flash_receive_buffer + 2);		// get actual Flash Status byte
	BIT TST ustat1 FL_BUSY_BIT;					// if flash is still busy erasing
	IF TF JUMP erase_flash_sector_status;		// just issue another read status reg cmd
		
erase_flash_sector_exit:	

	r4 = FL_CMD_ERASE_SECTOR;					// logging purposes
	r8 = DM(flash_sector_erase + 3);			
	r12 = m6;
	r14 = m6;
	
	JUMP _exit_flash_command;					// _exit_flash_command routine
												// logs flash_msg_log and sets up for next 
												// flash command
_erase_flash_sector.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_write32_flash
//
//	Notes:	Performs a four byte transfer to the flash. Handles write enables 
//			and necessary shifting.	Also checks if address is invalid with 
//			respect to user flash space	
//		
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE	
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_WRITE32;				
//								--> User address	(0x0000 - 0x1FFF)
//								-->	Written User data 32 bit
//								--> 1
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1
//
//////////////////////////////////////////////////////////////////////////////////

_write32_flash:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if a spi command waiting to be done
	IF TF JUMP write32_flash_wait;				

write32_flash_init:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// check if initialization state is done
	IF TF JUMP write32_flash_step1;				
		
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);
	DM(flash_command) = r14;					// save this variable for logging later on
	r14 = DM(i1, m6);
	DM(flash_address) = r14;					//	
	r14 = DM(i1, m6);
	DM(flash_data32) = r14;						//	the data word to be written to flash
	DM(flash_data32_temp) = r14;
	i1 = m5;	
	// IMPORTANT do not update i1 to tail pointer or else loose proper sequence 
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT;					// toggle bit state
	DM(flash_spi_service_state) = ustat1;
	
	CALL _qualify_flash_address;				// check if address location is valid
	
	r14 = DM(flash_invalid_address);			// if this is not set
	r14 = pass r14;								// address is invalid
	IF NE JUMP write32_flash_exit;				
	
write32_flash_step1:	
// if it went here this means that the flash address is valid so continue commands

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1  FL_SPI_STEP1;				// check if step 1 is done already
	IF TF JUMP write32_flash_step2;				// if done go to step 2
		
	r4 = flash_wren;							// enable write flash
	CALL _spi_add_queue;						

	DM(flash_receive_buffer) = m6;				// Necessary for spi handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT | FL_SPI_STEP1;	// setting state bits
	DM(flash_spi_service_state) = ustat1;
	
	RTS;
	
write32_flash_step2:		
write32_flash_enable:							// step 2 is to stage the next spi transfer

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1  FL_SPI_STEP2;				// check if this step is done
	IF TF JUMP write32_flash_step3;				// if done do next

	// Form needed address and modify flash_read variable first before
	// sending as a spi packet
	r14 = FL_SEND4;
	DM(flash_write_cntr) = r14;					// to be used to count written bytes;
	r14 = -24;									// first value needed to shift 32 bits
	DM(flash_shift) = r14;						// use for shifting data32
		
	r14 = DM(flash_high_byte_addr);
	DM(flash_write  + FL_MSADDR) = r14;			// save high byte address
		
	r14 = DM(flash_mid_byte_addr);
	DM(flash_write  + FL_MIDADDR) = r14;
	
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1  FL_SPI_STEP2;				// check if spi command is sent already
	DM(flash_spi_service_state)  = ustat1;

write32_flash_step3:
write32_next_byte:									

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1  FL_SPI_STEP3;				// check if spi command is sent already
	IF TF JUMP write32_flash_step4;				// if sent check if particular command is done	
		
	r14 = DM(flash_low_byte_addr);
	DM(flash_write  + FL_LSADDR) = r14;			// save low byte address
	r14 = r14 + 1;
	DM(flash_low_byte_addr) = r14;				// post increment for new address
	
	r14 = DM(flash_data32_temp);				// get 32 bit word
	r4 = DM(flash_shift);						// flash shift will get numbers
												// -24, -16 , -8
	r14 = LSHIFT r14 by r4;
	r15 = FL_BYTE_MASK; 						// get byte and form
	r14 = r15 and r14;							// flash write spi packet
	DM(flash_write  + FL_DATA_LOCATION) = r14;
	
	r15 = 8;									// the intention is to have
	r4 = r4 + r15;								// a decreasing shift value
	DM(flash_shift) = r4;						// so we get  the most significant
												// byte first 
	r4  = flash_write;
	CALL _spi_add_queue;						// flash write is non handshaked
												// because flash_rdsr will take care
												// of the 'BUSY' state
	DM(flash_receive_buffer) = m6;				// Re arm not ready

	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1  FL_SPI_WAIT | FL_SPI_STEP3;	// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;
	
	RTS;

write32_flash_step4:	
write32_byte_status:		

	r4 = flash_rdsr;							// add spi command to read 
	CALL _spi_add_queue;						// status register
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi transfer
		
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1  FL_SPI_WAIT | FL_SPI_STEP4;	// toggle state bits
	DM(flash_spi_service_state) = ustat1;
	
	RTS;

write32_flash_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi transfer

	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1  FL_SPI_WAIT ;				// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;
		
	ustat1 = DM(flash_spi_service_state);

	BIT TST ustat1  FL_SPI_STEP4;				// step 4 check if byte transfer done
	IF TF JUMP write_flash_busy_test;			
	
	BIT TST ustat1  FL_SPI_STEP3;				// step 3 is issuing the actual write cmd
	IF TF JUMP write32_flash_step4;				
	
	BIT TST ustat1  FL_SPI_STEP1;				// step 1 check if wren issued 
	IF TF JUMP write32_flash_step2;				

	RTS;
	
write_flash_busy_test:	
		
	ustat1 = DM(flash_receive_buffer + 2);		// get actual Flash Status byte
	BIT TST ustat1 FL_BUSY_BIT;
	IF TF JUMP write32_byte_status;
	
	r14 = DM(flash_write_cntr);					// the counter is initialized with 3
	r14 = r14 - 1;								// we are counting down before
	IF LT JUMP write32_flash_exit;
	DM(flash_write_cntr) = r14;					// update the counter value
	
	ustat1 = DM(flash_spi_service_state);		// stage next byte transfer
	BIT CLR ustat1 FL_SPI_STEP1 | FL_SPI_STEP3 | FL_SPI_STEP4 ;	
	DM(flash_spi_service_state) = ustat1;

	JUMP write32_flash_step1;
	
write32_flash_exit:	

	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_DONE;					// set this to say 32 bit transfer
	DM(flash_spi_service_state) = ustat1;		// is done
	
	r4 = DM(flash_sector_command_type);			// if write_flash_sector handles this
	r4 = pass r4;								// this variable is set
	IF NE JUMP _write_flash_sector;				// if so exit handling
												// is different if sector based

// exit sequence if word command not sector	based											
	r4 = FL_CMD_WRITE32;						// exit flash parameters
	r8 = DM(flash_address);						// log address
	r12 = DM(flash_data32);						// log 32 bit read flash data
	r14 = m5;
	
	JUMP _exit_flash_command;

_write32_flash.end:
		
//////////////////////////////////////////////////////////////////////////////////
//
//	_read32_flash
//
//	Notes:	Performs a four byte transfer from the flash and records/reforms
//			read bytes into a 32 bit word.
//		
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE	
//
//	Return value:			@ flash_msg_log	(four word)
//								-->	FL_CMD_READ32;				
//								--> User address	(0x0000 - 0x1FFF)
//								-->	Read flash data 32 bit
//								--> 1
//
//	Modified register:		r4, r8, r12, r14, b1, i1, l1, ustat1
//
//////////////////////////////////////////////////////////////////////////////////
_read32_flash:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP read32_flash_wait;				// if sent check if particular command is done	

read32_flash_init:
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// check if this state is done
	IF TF JUMP read32_flash_step1;				// if so go to next step
		
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;
	
	r14 = DM(i1, m6);
	DM(flash_command) = r14;					// get words for logging purposes
	r14 = DM(i1, m6);							// later on
	DM(flash_address) = r14;					//
	
	CALL _qualify_flash_address;				// check if address location is valid
	
	r14 = DM(flash_invalid_address);			// if this is not set
	r14 = pass r14;								// address is invalid
	IF NE JUMP read32_flash_exit;	

read32_flash_step1:		
	// Form needed address and modify flash_read variable first before
	// sending as a spi packet

	r14 = DM(flash_low_byte_addr);
	DM(flash_read32  + FL_LSADDR) = r14;		// save low byte address
	r14 = DM(flash_mid_byte_addr);
	DM(flash_read32  + FL_MIDADDR) = r14;
	r14 = DM(flash_high_byte_addr);
	DM(flash_read32  + FL_MSADDR) = r14;		// save high byte address
	
	// IMPORTANT do not update i1 to tail pointer or else loose proper sequence 
	r4  = flash_read32;							// issue 4 byte read command
	CALL _spi_add_queue;						// a read sequence is different and simpler
												// than a write sequence
												
	DM(flash_receive_buffer) = m6;				// for spi handshake
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;

read32_flash_wait:	

	r14 = DM(flash_receive_buffer);				// if first word  of receive buffer cleared 
	r14 = pass r14;								// this means that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// for spi handshake

	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;
												// constructing 8 bits to 32 bits MSB first
	r14 = DM(flash_receive_buffer+5);			// retrieve read data from receive buffer
		
	r14 = LSHIFT r14 by 8;
	r15 = DM(flash_receive_buffer+6);			// retrieve read data from receive buffer
	r14 = r14 or r15;

	r14 = LSHIFT r14 by 8;
	r15 = DM(flash_receive_buffer+7);			// retrieve read data from receive buffer
	r14 = r14 or r15;

	r14 = LSHIFT r14 by 8;
	r15 = DM(flash_receive_buffer+8);			// retrieve read data from receive buffer
	r14 = r14 or r15;
	DM(flash_data32) = r14;

read32_flash_exit:

	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_DONE;					// set this to say 32 bit transfer
	DM(flash_spi_service_state) = ustat1;		// is done
	
	r4 = DM(flash_sector_command_type);			// if read_flash_sector handles this
	r4 = pass r4;								// this variable is set
	IF NE JUMP _read_flash_sector;				// if so exit handling
				
	r4 = FL_CMD_READ32;							// exit flash parameters
	r8 = DM(flash_address);						// log address
	r12 = DM(flash_data32);						// log 32 bit read flash data
	r14 = m5;
	
	JUMP _exit_flash_command;

_read32_flash.end:	
		
//////////////////////////////////////////////////////////////////////////////////
//
//	_exit_flash_command
//
//	Notes:		Standard exit sequence for every flash based command
//				Saves info for the flash_msg_log and increments the flash queue
//				to be ready for next command
//		
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			NONE
//														
//	Modified register:  	i1, b1, l1,m1
//
//////////////////////////////////////////////////////////////////////////////////
_exit_flash_command:

	b1 = flash_msg_log;							// point to flash msg lob
	l1 = FL_MSG_LOG_SIZE;
	i1 = DM(flash_msg_log_head_ptr);

	DM(i1, m6) = r4;							// save command and other info
	DM(i1, m6) = r8;
	DM(i1, m6) = r12;							// keep four word boundary
	DM(i1, m6)  = r14;
	
	DM(flash_msg_log_head_ptr) = i1;			// update variable
	DM(flash_spi_service_state) = m5;			// zero out this variable for next cmds
	
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);				//
	l1 = FL_QUEUE_SIZE;							// advance tail pointer by queue skip (3)

	m1 = FL_QUEUE_SKIP;							// to service next flash command
	MODIFY(i1, m1);								
	DM(flash_queue_head_ptr) = i1;
	
	RTS;
_exit_flash_command.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_qualify_flash_address
//
//	Notes:	Checks if address location is within user space boundaries.
//			User is allocated 8k of 32 bit words
//			User address locations 0 - 1FFF are available for user use
//			Anything outside address is invalid and handler will advance
//			flash queue and ignore the flash transfer command
//
//	Written by Danville Signal Processing
//
//	Date:					31 May 05
//
//	Calling parameters: 	DM(flash_address)
//
// 	Return value:			DM(flash_high_byte)
//							DM(flash_mid_byte)
//							DM(flash_low_byte)
//														
//	Modified register:  	r13, r14, r15 
//
//////////////////////////////////////////////////////////////////////////////////
_qualify_flash_address:

	DM(flash_invalid_address) = m5;				// zero out before testing

	r14 = DM(flash_address);					// check for low boundary
	r15 = FL_USER_START32;						// violation
	COMP(r14, r15);
	IF LT JUMP qualify_flash_address_invalid;	
	
	r14 = DM(flash_address);					// check for high boundary
	r15 = FL_USER_END32;						// violation
	COMP(r14, r15);
	IF GT JUMP qualify_flash_address_invalid;

	r14 = LSHIFT r14 by 2;						// r14 still holds flash address
	r15 = FL_BASE_ADDR;							// adjust to change context from
	r15 = r15 + r14;							// 32 bit words to bytes
												// and shift to user space
												// found @ last block
	r14 = FL_BYTE_MASK;							
	r13 = r15 and r14;
	DM(flash_low_byte_addr) = r13;				// address is right justified
	
	r15 = LSHIFT r15 by -8;						// get low,mid and high byte
	r13 = r15 and r14;							// to change spi packet address
	DM(flash_mid_byte_addr) = r13;					// location
	
	r15 = LSHIFT r15 by -8;
	r13 = r15 and r14;
	DM(flash_high_byte_addr) = r13;
		
	RTS;
	
qualify_flash_address_invalid:

// software goes to here there is no spi commands execute and
// the flash queue is advance to the next command

	DM(flash_invalid_address) = m6;				// zero out before testing

	DM(flash_address) = m7;						// sign for a invalid addresslog address
	DM(flash_data32) = m5;						// log 32 bit read flash data
	
	RTS;

_qualify_flash_address.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_write_flash_sector
//
//	Notes:	Manages multiple writes to a flash sector.  It uses _write32_flash
//			as a low level handler.  Amount of transfers is proportional to the 
//			the size of the dsp side variable to be transferred from. The user
//			should supply the size of the dsp side variable and this size should
//			be less than the maximum which is 1024.  It is important
// 			that user has issued the unprotect flash and erase sector commands
//			first before calling a flash command.  A user flash sector is worth 
//			1 K words (32 bit words).  
//
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_WRITE_SECTOR;				
//								--> sector number		(FL_SECTOR0 - FL_SECTOR7)
//								-->	source address
//								--> transfer length
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1, i4
//
//////////////////////////////////////////////////////////////////////////////////
_write_flash_sector:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP write_flash_sector_wait;			// and just waiting for completion

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_DONE;					// test if bit set for 32 bit transfer compeltion
	IF TF JUMP write_flash_sector_transfer_done;
	
write_flash_sector_init:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_SECTOR_INIT;			// check if spi command is sent already
	IF TF JUMP write_flash_sector_next_word;	// and just waiting for completion
// this state initializes the whole sector write state machine

	DM(flash_sector_command_type) = m6;			// set this variable for other flash commands
	
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);
	DM(flash_sector_command) = r14;				// save this variable for logging later on
	r14 = DM(i1, m6);
	DM(flash_sector_addr) = r14;				//
	r14 = DM(i1, m6);
	DM(flash_source_addr) = r14;				// needed for saving
	DM(flash_sector_ptr) = r14;					// initialize pointer to data source	

	r14 = DM(i1, m6);
	DM(flash_sector_transfer_size) = r14;		
	DM(flash_sector_transfer_cntr) = r14;		// will be used to count # of transfers later
	
// form starting address for sector transfer

	r14 = DM(flash_sector_addr);				// transform sector number to user address number
	r14 = LSHIFT r14 by 8;						// the sector number is assigned when using absolute
	r4 =  FL_SECTOR_INIT_MASK;					// byte wide addressing
	r14 = r14 + r4;								// all the operations here does the 
	r4 =  FL_SECTOR_END_MASK;					// steps to transform that to a user address
	r14 = r4 and r14;							// 
	r4 = FL_BASE_ADDR;							
	r14 = r14 - r4;								// subtract lowest user addr computed 		
	r14 = LSHIFT r14 by -2;						// divide by 4 effect
	DM(flash_address) = r14;					// this variable is now in between 0x0000- 0x1fff
// flash_address variable will be divided by qualify_flash_address																					
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_SECTOR_INIT | FL_SPI_INIT;// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;
// Take note that by setting FL_SPI_INIT the initialization in the write32_flash
// routine is ignored.

write_flash_sector_next_word:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_SECTOR_SETUP;			// after this step write32_flash takes over	
	IF TF JUMP write_flash_sector_wait;
	
	CALL _qualify_flash_address;				// converts flash address to 3 bytes

	l1 = m5;										// make sure that it is not circular
	i1 = DM(flash_sector_ptr);					// get data from current pointer
	r14 = DM(i1, m6);							// get ready for next
	DM(flash_sector_ptr) = i1;
	DM(flash_data32_temp) = r14;				// the actual data to be transmitted by write32_flash	

	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_SECTOR_SETUP;			// after this step write32_flash takes over	
	DM(flash_spi_service_state) = ustat1;
	
write_flash_sector_wait:

	JUMP _write32_flash;

write_flash_sector_transfer_done:
// entering this stage means that a 32 bit write is done towards the flash
// steps to do determine if there are still words to be sent

	r14 = DM(flash_sector_transfer_cntr);		// transfer done so decrement
	r14 = r14 - 1;				
	IF EQ JUMP write_flash_sector_exit;			// is this the last word sent?
	
	DM(flash_sector_transfer_cntr) = r14;		// save counter
// if still words to send , increment flash address 
	
	r14 = DM(flash_address);
	r14 = r14 + 1;
	DM(flash_address) = r14;
	
// clear states the sector setup and the rest of the states in write32
// namely steps 1,2,3, 4 and spi_done just like calling write32 again	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_DONE | FL_SPI_SECTOR_SETUP | FL_SPI_STEP1  | FL_SPI_STEP2 | FL_SPI_STEP3 | FL_SPI_STEP4 ;	
	DM(flash_spi_service_state) = ustat1;
	
	JUMP write_flash_sector_next_word;
	
write_flash_sector_exit:

	DM(flash_sector_command_type) = m5;			// clear this variable for other flash commands

	r4  = DM(flash_sector_command);				// exit flash parameters
	r8  = DM(flash_sector_addr);				// log sector address
	r12 = DM(flash_source_addr);				// log 32 bit read flash data
	r14 = DM(flash_sector_transfer_size);

	JUMP _exit_flash_command;

_write_flash_sector.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	_read_flash_sector
//
//	Notes:	Command handler for a flash read sector read command.  Uses
//			_read32_flash as a low level handler.  Essentially branches to
//			_read32_flash repeatedly propotional to the amount of words
//			needed to be read. Transfer from flash to dsp memory
//
//	Written by Danville Signal Processing
//
//	Date:					1 June 05
//
//	Calling parameters: 	NONE
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_READ_SECTOR;				
//								--> sector number		(FL_SECTOR0 - FL_SECTOR7)
//								-->	destination address
//								--> transfer length
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1
//
//
//////////////////////////////////////////////////////////////////////////////////
_read_flash_sector:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if spi command is sent already
	IF TF JUMP read_flash_sector_wait;			// and just waiting for completion

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_DONE;					// test if bit set for 32 bit transfer compeltion
	IF TF JUMP read_flash_sector_transfer_done;

read_flash_sector_init:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_SECTOR_INIT;			// check if spi command is sent already
	IF TF JUMP read_flash_sector_next_word;		// and just waiting for completion
// this state initializes the whole sector write state machine

	DM(flash_sector_command_type) = m6;			// set this variable for other flash commands
	
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);
	DM(flash_sector_command) = r14;				// save this variable for logging later on
	r14 = DM(i1, m6);
	DM(flash_sector_addr) = r14;				//
	r14 = DM(i1, m6);
	DM(flash_destination_addr) = r14;			// needed for saving
	DM(flash_sector_ptr) = r14;					// init pointer to source	

	r14 = DM(i1, m6);
	DM(flash_sector_transfer_size) = r14;		
	DM(flash_sector_transfer_cntr) = r14;		// will be used to count # of transfers later
	
// form starting address for sector transfer

	r14 = DM(flash_sector_addr);				// transform sector number to user address number
	r14 = LSHIFT r14 by 8;						// the sector number is assigned when using absolute
	r4 =  FL_SECTOR_INIT_MASK;					// byte wide addressing
	r14 = r14 + r4;								// all the operations here does the 
	r4 =  FL_SECTOR_END_MASK;					// steps to transform that to a user address
	r14 = r4 and r14;							// 
	r4 = FL_BASE_ADDR;							
	r14 = r14 - r4;								// subtract lowest user addr computed 		
	r14 = LSHIFT r14 by -2;						// divide by 4 effect
	DM(flash_address) = r14;					// this variable is now in between 0x0000- 0x1fff
// flash_address variable will be divided by qualify_flash_address																					
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_SECTOR_INIT | FL_SPI_INIT;// check if spi command is sent already
	DM(flash_spi_service_state) = ustat1;
// Take note that by setting FL_SPI_INIT the initialization in the _read32_flash
// routine is ignored.

read_flash_sector_next_word:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_SECTOR_SETUP;			// after this step _read32_flash takes over	
	IF TF JUMP read_flash_sector_wait;
	
	CALL _qualify_flash_address;				// converts flash address to 3 bytes
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_SECTOR_SETUP;			// after this step _read32_flash takes over	
	DM(flash_spi_service_state) = ustat1;

read_flash_sector_wait:

	JUMP _read32_flash;
	
read_flash_sector_transfer_done:	
// entering this stage means that a 32 bit write is read from the flash

	r14 = DM(flash_address);					// increment address for next read
	r14 = r14 + 1;
	DM(flash_address) = r14;
	
	l1 = m5;									// make sure that it is not circular
	i1 = DM(flash_sector_ptr);					// pointer where to save
	r14 = DM(flash_data32);						// get read data 
	DM(i1, m6) = r14;							// save
	DM(flash_sector_ptr) = i1;					// update increment addr
		
// clear states the sector setup and the rest of the states in write32
// namely steps 1,2,3, 4 and spi_done just like calling _read32_flash again	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_DONE | FL_SPI_SECTOR_SETUP | FL_SPI_STEP1  | FL_SPI_STEP2 | FL_SPI_STEP3 | FL_SPI_STEP4 ;	
	DM(flash_spi_service_state) = ustat1;

	r14 = DM(flash_sector_transfer_cntr);		// transfer done so decrement cntr
	r14 = r14 - 1;				
	IF EQ JUMP read_flash_sector_exit;			// is this the last word to be read?
	
	DM(flash_sector_transfer_cntr) = r14;		// save counter
		
	JUMP read_flash_sector_next_word;
	
read_flash_sector_exit:

	DM(flash_sector_command_type) = m5;			// clear this variable for other flash commands

	r4  = DM(flash_sector_command);				// exit flash parameters
	r8  = DM(flash_sector_addr);				// log sector address
	r12 = DM(flash_destination_addr);			// destination variable in dsp
	r14 = DM(flash_sector_transfer_size);		// amount of words read

	JUMP _exit_flash_command;
	
_read_flash_sector.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	_protect_flash_section
//
//	Notes:		This function is specifically applicable for the ATMEL AT26F004.
//				The whole flash memory space is divided into 10 blocks of memory
//				that can be protected.  Three out of the ten blocks cover the user
//				space.  This subroutine is the handler for protecting the user flash
//				space. With respect to this library, the blocks that cover the user 
//				flash memory space are defined as follows:
//				FL_ATMEL_SECTION1, FL_ATMEL_SECTION2 and FL_ATMEL_SECTION3.
//
//				Protecting a 'section' involves three processes namely
//					1. issuing a write enable command
//					2. issuing the protection command
//					3. tracking the status register for completion
//
//	Written by Danville Signal Processing
//
//	Date:					15 July 06
//
//	Calling parameters: 	NONE
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_PROTECT_SECTION
//								--> section number 	(ATMEL_SECTION1 - ATMEL_SECTION3)
//								-->	1
//								--> 1
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1
//
//
//////////////////////////////////////////////////////////////////////////////////

_protect_flash_section:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if wait flag is set
	IF TF JUMP protect_flash_section_wait;		// if so go to wait state handler

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// the init state is issuing a write enable command
	IF TF JUMP protect_flash_section_step_1;	// if done go to next step
	
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);							// this word is the command
	r14 = DM(i1, m6);							// the second word is the section to be protected
	
	DM(flash_protect_section + 3) = r14;		// get the value of the section to be
												// unprotected and save to spi packet
	
	// The write enable command should be issued prior to protecting sectors
	r4 = flash_wren;					
	CALL _spi_add_queue;						// Issue write enable command
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
			
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT | FL_SPI_WAIT;	// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		// and make state machine to wait
	
	JUMP protect_flash_section_wait;

protect_flash_section_step_1:	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP1;				// the init state is changing the wrsr packet
	IF TF JUMP protect_flash_section_wait;		// if done go to other handler

	r4 = flash_protect_section;					// Issue a protect section command	
	CALL _spi_add_queue;						// at this point the packet has the proper section number 
												// to be protected
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP1 | FL_SPI_WAIT;	// set step 1 and the wait state flag
	DM(flash_spi_service_state) = ustat1;
	
	JUMP protect_flash_section_wait;

protect_flash_section_read_status:	

	r4 = flash_rdsr;							// add spi command to read 
	CALL _spi_add_queue;						// status register
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi transfer
		
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP2 | FL_SPI_WAIT;	// step 2 is set, wait flag is also set
	DM(flash_spi_service_state) = ustat1;		// step 2 is tracking the status register	
	
protect_flash_section_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// clear the wait state flag
	DM(flash_spi_service_state) = ustat1;
	
	BIT TST ustat1 FL_SPI_STEP1;				// step 1 is to issue the protect section command
	IF NOT TF JUMP protect_flash_section_step_1;// check if this has been issued already, otherwise
												// go to step 1
	
	BIT TST ustat1 FL_SPI_STEP2;				// step 2 is to issue a read status register command
	IF NOT TF JUMP protect_flash_section_read_status;	// to verify if that the protection command is fully 
												// serviced internally in the flash chip.
												// if set it is time to check the status register
protect_flash_section_read_status_test:

	// At this point we are reading the flash status register
	// since last command is reading the status register.			
	ustat1 = DM(flash_receive_buffer + 2);		// get actual flash status register
	BIT TST ustat1 FL_BUSY_BIT;					// if status register is still busy issue another 
	IF TF JUMP protect_flash_section_read_status;	// status read command

														
protect_flash_section_exit:

	r4 = FL_CMD_PROTECT_SECTION;				// logging purposes
	r8 =  DM(flash_protect_section + 3) ;		// log ATMEL section that has been protected
	r12 = m6;
	r14 = m6;
	
	JUMP _exit_flash_command;					// _exit_flash_command routine

_protect_flash_section.end:



//////////////////////////////////////////////////////////////////////////////////
//
//	_unprotect_flash_section
//
//	Notes:		Just like the _protect_flash_section, this subroutine is only 
//				available as a feature of the ATMEL AT26F004.  This subroutine 
//				unprotects one of the three section available to the user 
//				Unprotecting a block of memory which we will call as a section
//				will allow write operations to that block of memory.  The sections
//				are named as follows:
//				FL_ATMEL_SECTION1, FL_ATMEL_SECTION2 and FL_ATMEL_SECTION3.
//
//				Unprotecting a 'section' involves three processes namely
//					1. issuing a write enable command
//					2. issuing the unprotection command
//					3. tracking the status register for completion
//
//	Written by Danville Signal Processing
//
//	Date:					15 July 06 
//
//	Calling parameters: 	NONE
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_UNPROTECT_SECTION
//								--> section number 	(ATMEL_SECTION1 - ATMEL_SECTION3)
//								-->	1
//								--> 1
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1
//
//
//////////////////////////////////////////////////////////////////////////////////
_unprotect_flash_section:

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if the wait state flag is set
	IF TF JUMP unprotect_flash_section_wait;	// if so go to the waith state handler

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_INIT;					// the init state is issuing a write enable command
	IF TF JUMP unprotect_flash_section_step_1;	// if this step is done go to the next step
	
	
	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);							// this is the command word
	r14 = DM(i1, m6);							// this contains the section to be unprotected

	DM(flash_unprotect_section + 3) = r14;		// get the value of the section to be
												// unprotected and save to spi packet
	
	// The write enable command should be issued prior to protecting sectors
	r4 = flash_wren;					
	CALL _spi_add_queue;						// Issue write enable command
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
			
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT | FL_SPI_WAIT;	// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		// and set the wait state 	
	
	JUMP unprotect_flash_section_wait;

unprotect_flash_section_step_1:	

	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_STEP1;				// step is issuing the unprotect section command
	IF TF JUMP unprotect_flash_section_wait;	// if this step is done go to next step

	r4 = flash_unprotect_section;				// issue unprotect command	
	CALL _spi_add_queue;						// spi packet is ready at this point
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
	
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP1 | FL_SPI_WAIT;	// set the step 1 flag along with the wait state
	DM(flash_spi_service_state) = ustat1;		
	
	JUMP unprotect_flash_section_wait;
	
unprotect_flash_section_read_status:	

	r4 = flash_rdsr;							// add spi command to read 
	CALL _spi_add_queue;						// status register
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi transfer
		
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_STEP2 | FL_SPI_WAIT;	// step 2 is set, wait flag is also set
	DM(flash_spi_service_state) = ustat1;		// step 2 is tracking the status register
	
unprotect_flash_section_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// clear the wait state flag
	DM(flash_spi_service_state) = ustat1;
	
	BIT TST ustat1 FL_SPI_STEP1;				// check if step 1 is done
	IF NOT TF JUMP unprotect_flash_section_step_1;	// if not yet done go to step 1 

	BIT TST ustat1 FL_SPI_STEP2;				// step 2 is to issue a read status register command
	IF NOT TF JUMP unprotect_flash_section_read_status;	// to verify if that the protection command is fully 
												// serviced internally in the flash chip.
												// if set it is time to check the status register
unprotect_flash_section_read_status_test:

	// At this point we are reading the flash status register
	// since last command is reading the status register.			
	ustat1 = DM(flash_receive_buffer + 2);		// get actual flash status register
	BIT TST ustat1 FL_BUSY_BIT;					// check if the busy bit is cleared for command completion
	IF TF JUMP unprotect_flash_section_read_status;
																										
unprotect_flash_section_exit:

	r4 = FL_CMD_UNPROTECT_SECTION;				// logging purposes
	r8 =  DM(flash_unprotect_section + 3) ;		// log ATMEL section that has been unprotected
	r12 = m6;
	r14 = m6;
	
	JUMP _exit_flash_command;					// _exit_flash_command routine
	
_unprotect_flash_section.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_read_protection_register
//
//	Notes:		As discussed in the protect and unprotect subroutines, there are 
//				three out of ten memory blocks are allocated for user flash
//				memory space.  As a feature available in the ATMEL AT26F004, each 
// 				user flash  memory block can be protected. For each block there is
//				an associated protection register which reflects the status of
//				protection for the particular block or with respect to this code
//				library, a section. This subroutine handles the process of reading
//				the protection register.
//				
//
//	Written by Danville Signal Processing
//
//	Date:					15 July 06 
//
//	Calling parameters: 	NONE
//
//	Return value:		@ flash_msg_log	(four word)
//								-->	FL_CMD_READ_PROTECT_REG
//								--> section number 	(ATMEL_SECTION1 - ATMEL_SECTION3)
//								-->	protection register value
//								--> 1
//
//	Modified register:	r4, r8, r12, r14, b1, i1, l1, ustat1
//
//
//////////////////////////////////////////////////////////////////////////////////
_read_protection_register:
	
	ustat1 = DM(flash_spi_service_state);
	BIT TST ustat1 FL_SPI_WAIT;					// check if the wait state is set
	IF TF JUMP read_protection_register_wait;	// if set go to wait state handler

	b1 = flash_queue;							// grab the command type from queue
	i1 = DM(flash_queue_head_ptr);
	l1 = FL_QUEUE_SIZE;

	r14 = DM(i1,m6);							// this is the command word
	r14 = DM(i1, m6);							// this contains the section where we need to read
												// the protection register

	DM(flash_read_protection_reg + 3) = r14;	// get the value of the section to be
												// verified and save to spi packet
	

	r4 = flash_read_protection_reg;					
	CALL _spi_add_queue;						// Issue read protection register command
	
	DM(flash_receive_buffer) = m6;				//	Set word for handshaking
			
	ustat1 = DM(flash_spi_service_state);
	BIT SET ustat1 FL_SPI_INIT | FL_SPI_WAIT;	// Say that command handler initial state is done
	DM(flash_spi_service_state) = ustat1;		
	
read_protection_register_wait:

	r14 = DM(flash_receive_buffer);				// if first word is cleared this means
	r14 = pass r14;								// that spi service is done
	IF NE RTS;				
	
	DM(flash_receive_buffer) = m6;				// necessary for next spi commands
	
	ustat1 = DM(flash_spi_service_state);
	BIT CLR ustat1 FL_SPI_WAIT;					// clear the wait state
	DM(flash_spi_service_state) = ustat1;
	
read_protection_register_exit:

	r4 = FL_CMD_READ_PROTECT_REG;					// logging purposes
	r8 =  DM(flash_read_protection_reg  + 3) ;		// log ATMEL section under protection verification
	r12 = DM(flash_receive_buffer + 5);				// the value of the protection register is found in the flash receive buffer
	r14 = m6;
	
	JUMP _exit_flash_command;	
	
_read_protection_register.end:



// -- -- -- F L A S H    C O D E     B A S E     E   N   D    -- -- -- -- -- //





// -- -- -- E E P R O M    C O D E     B A S E   S T A R T    -- -- -- -- -- //
/////////////////////////////////////////////////////////////////////////
// 
//	Usage of EEPROM commands
//
//	To read the status register of the eeprom
//			r4 = EE_CMD_STATUS;	
//			CALL _eeprom_add_queue;
//
//  To allow eeprom to be writable	
//			r4 = EE_CMD_UNPROTECT;
//			CALL _eeprom_add_queue;
//
// 	To disallow further writes toward the eeprom
//			r4 = EE_CMD_PROTECT;
//			CALL _eeprom_add_queue;
//
//	To read a byte from location 0x0000 
//			r4 = EE_CMD_READ8;	
//			r8 = 0x0000;
//			CALL _eeprom_add_queue;
//
//	To read a 16 bit word from location 0x0FFE 
//			r4 = EE_CMD_READ16;	
//			r8 = 0x0FFE;
//			CALL _eeprom_add_queue;
//
//	To read a 32 bit word from location 0x1FFC 
//			r4 = EE_CMD_READ32;	
//			r8 = 0x1FFC;
//			CALL _eeprom_add_queue;
//
//  To write a byte at starting location (0x0000) with data 0xA5		
//			r4 = EE_CMD_WRITE8;	
//			r8 = 0x0000;
//			r12 = 0xA5;
//			CALL _eeprom_add_queue;
//	
//  To write a 16 bit word at starting location (0x0FFE) with data 0x1234
//			r4 = EE_CMD_WRITE16;	
//			r8 = 0x0FFE;
//			r12 = 0x1234;
//			CALL _eeprom_add_queue;
//
//  Write a 32 bit word at starting location (0x1FFC) with data 0x5678ABCD
//			r4 = EE_CMD_WRITE32;	
//			r8 = 0x1FFC;
//			r12 = 0x5678ABCD;
//			CALL _eeprom_add_queue;
//
//	To service eeprom commands, the subroutine _eeprom_manager should be coupled
//	with _spi_manager in the 'forever' loop.
//
//	The USER EEPROM memory resource in the dspstak sx2 zx2 platform has an address
//	range from 0x0000 to 0x1FFF, which is an 8 kilobyte memory space. 
//	The user should however be aware that the last 256 bytes are the same 256 bytes 
//	accessable by the user in the upload mode. The 256 bytes are considered
//	reserved by Danville Signal and it is advised that the user	should take precaution
//  not to cross this address boundary.  Therefore, the official user eeprom
//	memory space is from 0x0000 to 0x1EFF.
//
//	The EEPROM residing in a dspstak system is primarily an 8 bit device.
//	This library has made provision for data access with 16 and 32 bit words.
//	The user should be aware that there is a page wrap  issue associated
//	with multiple data access.  This is not relevant if all data access are 
//	all 8 bit wide.  This library has avoided this wrap around issue by controlling
//	the address for 16 and 32 bit word access.  This is done by zeroing out
//	the lsbs of the address.  In this way data access is guaranteed to be
//  always within a page and a wrap around is not possible. This wrap around
//	 issue also works if you go at the edge of the address space. For example,
//  if you issue an address of 0x1FFF and you are reading a 32 bit word.  The
//  actual data you are reading will wrap around and the data access will be with
//  addresses 0x1FFF, then 0x000, 0x0001 and lastly 0x0002.  All wrap around
//	possibilities are avoided by chopping some lsbs.  For the same example, the 
//  effective address will be 0x1FFC (with 2 lsbs = 0)  Effectively, the data
//	access if from address locations 0x1FFC, 0x1FFD, 0x1FFE and 0x1FFF.  The library
//	automatically does this for you. As to avoid confusion, it is suggested
//  that a memory map plan for different data widths within the eeprom should 
//	be made.
//
//	The user also has the capability of tracking executed eeprom commands.  
//  There is a data structure called eeprom_msg_log which 'logs' all executed 
//	commands and this data structure follows are three word boundary.  The 
//  three words logged for each executed command are the eeprom command, address/data
//	and data.  Word 2 and 3 vary depending on the eeprom command issued.  The
//	user can use the eeprom_msg_log_tail_ptr as a moving pointer to track
//	within the data structure.  While tracking the three word boundary should
//	be observed.
//
/////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////
//
//	_init_user_eeprom
//
//	Notes:
//			Declares the eeprom as a spi device according to the danville
//			SPI zx protocol.  
//
//	Written by Danville Signal Processing
//
//	Date:					10 June  05
//
//	Calling parameters: 	NONE
//
// 	Return value:			NONE
//			
//	Modified register:  	r4, r8, r12
//
//////////////////////////////////////////////////////////////////////////////////
_init_user_eeprom:

	r4 = SPI_DEVICE_EE;					// SPI Device Number	
	r8 =  eeprom_device_settings;		// SPI device parameters
	r12 = eeprom_receive_buffer;		// Buffer used for each individual byte 
	
	CALL _init_spi_device;				// declare device parameters for eeprom
	
	RTS;
_init_user_eeprom.end:


///////////////////////////////////////////////////////////////////////////////////
//
//	_eeprom_add_queue
//
//	Notes:
//			Adds an eeprom command to command queue.  The queue will be serviced 
//			by _eeprom_manager.  Please see eeprom command usage.
//
//	Written by Danville Signal Processing
//
//	Date:					10 June  05
//
//	Calling parameters: 	r4  = EEPROM command
//							r8  = EEPROM address/data if necessary 
//							r12 = EEPROM data if necessary
//
// 	Return value:			NONE
//			
//	Modified register:  	b1, i1, l1
//
//////////////////////////////////////////////////////////////////////////////////
_eeprom_add_queue:

	b1 = eeprom_queue;					// point to eeprom command queue
	i1 = DM(eeprom_queue_tail_ptr);		// tail ptr increments with new packets
	l1 = EE_QUEUE_SIZE;			
	
	DM(i1, m6) = r4;					// command, address, data 
	DM(i1, m6) = r8;					// parameters dependent on command
	DM(i1, m6) = r12;					// four word boundary is maintained
	
	DM(eeprom_queue_tail_ptr) = i1;		// update tail ptr
	
	RTS;

_eeprom_add_queue.end:	

///////////////////////////////////////////////////////////////////////////////////
//
//	_eeprom_manager
//
//	Notes:
//			Views the eeprom queue and fetches the current command to be serviced
//			branches to the particular handler for an EEPROM command.
//
//	Written by Danville Signal Processing
//
//	Date:					10 June  05
//
//	Calling parameters: 	NONE
//
// 	Return value:			r0 = 0 if eeprom command queue is empty
//							r0 = non zero if eeprom command queue not empty
//			
//	Modified registers:  	r0, r4, r8, r12, r14, r15, b1, i1, l1, i8, m8
//
//////////////////////////////////////////////////////////////////////////////////
_eeprom_manager:

	r0 = 0;								// return value in case eeprom queue is empty
	r14 = DM(eeprom_queue_head_ptr);	// check if head and tail are equal if not
	r15 = DM(eeprom_queue_tail_ptr);	// time to service eeprom commands
	COMP(r14, r15);
	IF EQ RTS;							// return 0 if empty

	r0 = 1;								// ensure return value is non zero
										// subsequent handlers should also return r0 = non '0'
										
	b1 = eeprom_queue;					// grab the command type from queue
	i1 = DM(eeprom_queue_head_ptr);
	l1 = EE_QUEUE_SIZE;
	
	r14 = DM(i1, m5);					// check if command is valid
	r15 = EE_INVALID_CMD;				// if non valid
	COMP(r14, r15);
	IF GE JUMP eeprom_invalid_command;	
	
	m8 = r14;							// get command number
	i8 = eeprom_manager_branch;	
	JUMP(m8, i8);						// and branch to command handler
																									
eeprom_manager_branch:					// get command type and go to 
										// command handler
	JUMP _read_eeprom_status;			// just read eeprom status register
	JUMP _protect_eeprom;				// protect whole eeprom from write processes
	JUMP _unprotect_eeprom;				// allow whole eeprom to have write processes
	JUMP _read_eedata8;					// read a byte from eeprom
	JUMP _read_eedata16;				// read 16 bit word from eeprom
	JUMP _read_eedata32;				// read 32 bit word from eeprom
	JUMP _write_eedata8;				// write a byte into eeprom
	JUMP _write_eedata16;				// write 16 bit word into eeprom
	JUMP _write_eedata32;				// write 32 bit word into eeprom
	
eeprom_invalid_command:					// if command is invalid skip to the next
										// command (skip by three)
    i1 = DM(eeprom_queue_head_ptr);
	m1 = EE_QUEUE_SKIP;					//modify the head pointer by three to satisfy
	MODIFY(i1 , m1);					// eeprom queue boundaries		
	DM(eeprom_queue_tail_ptr) = i1;		
											
	RTS;
_eeprom_manager.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_exit_eeprom_command
//
//	Notes:		Standard exit sequence for every eeprom based command
//				Saves info into the eeprom_msg_log and increments the eeprom queue
//				to be ready for next command
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	r4  = eeprom command
//							r8  = address/ data if necessary
//							r12 = data if necessary
//							* each command fills the msg log differently
//
// 	Return value:			NONE
//														
//	Modified register:  	i1, b1, l1,m1
//
//////////////////////////////////////////////////////////////////////////////////
_exit_eeprom_command:

	b1 = eeprom_msg_log;						// point to eeprom msg log
	l1 = EE_MSG_LOG_SIZE;
	i1 = DM(eeprom_msg_log_tail_ptr);

	DM(i1, m6) = r4;							// save command and other info
	DM(i1, m6) = r8;
	DM(i1, m6) = r12;							// keep three word boundary
		
	DM(eeprom_msg_log_tail_ptr) = i1;			// update variable
	DM(eeprom_spi_service_state) = m5;			// zero out this variable for next cmds
	
	b1 = eeprom_queue;							// point to eeprom queue
	i1 = DM(eeprom_queue_head_ptr);				//
	l1 = EE_QUEUE_SIZE;							// advance head pointer by queue skip (3)

	m1 = EE_QUEUE_SKIP;							// to service next eeprom command
	MODIFY(i1, m1);								
	DM(eeprom_queue_head_ptr) = i1;
	
	RTS;
_exit_eeprom_command.end:



//////////////////////////////////////////////////////////////////////////////////
//
//	_read_eeprom_status
//
//	Notes:	Issues a read status register command towards the eeprom and upon 
//			completion logs the command and the status register value in the 
//			eeprom_msg_log.	
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:		@ eeprom_msg_log	
//							--> EE_CMD_STATUS;	
//							--> EEprom status register value
//							--> 1
//														
//	Modified register:  	r4, r8, r12, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////
_read_eeprom_status:	

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP read_eeprom_status_wait;
	
	r4 = eeprom_rdsr;							// issue read status register via spi
	CALL _spi_add_queue;

	DM(eeprom_receive_buffer) = m6;				// re arm for next command
		
	ustat1 = DM(eeprom_spi_service_state);
	BIT SET ustat1 EE_SPI_INIT;					// first state done
	DM(eeprom_spi_service_state) = ustat1;

	RTS;
	
read_eeprom_status_wait:
	
	r15 = DM(eeprom_receive_buffer);			// check for spi handshake
	r15 = pass r15;
	IF NE RTS;


read_eeprom_status_exit:

	r4 = EE_CMD_STATUS;							// for logging purposes
	r8 = DM(eeprom_receive_buffer + 2);			
	r12 = m6;									

	JUMP _exit_eeprom_command;					// standard exit routine
				
_read_eeprom_status.end:					

//////////////////////////////////////////////////////////////////////////////////
//
//	_protect_eeprom and _unprotect_eeprom
//
//	Notes:	
//		Sends a write status register command with the BPLx bits set or cleared.
//		These bits being set disallows/allow  further writes towards the eeprom.  
//		It is necessary to track the status register if the write in progress has 
//		been done.  Prior to sending a write status command the write enable 
//		command should be issued. Subroutines jumps to _eeprom_write_handler to 
//		execute spi transfer.	
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ eeprom_msg_log	
//							--> EE_CMD_PROTECT or EE_CMD_UNPROTECT;	
//							--> 1
//							--> 1
//							
//	Modified register:  	ustat1
//
//////////////////////////////////////////////////////////////////////////////////	
_protect_eeprom:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP protect_eeprom_redirect;			// if so jump to next state

	ustat1 = DM(eeprom_wrsr + 2);
	BIT SET ustat1 EE_STATUS_BP1 | EE_STATUS_BP0;
	DM(eeprom_wrsr + 2) = ustat1;				// modify eeprom_wrsr data struct

	ustat1 = EE_CMD_PROTECT;
	DM(eeprom_command) = ustat1;				// for logging purposes
	DM(eeprom_addr) = m6;						// force to one
	DM(eeprom_data) = m6;		
	
	DM(eeprom_write_type) = m5;					// signify that this write is for the status register
	
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

protect_eeprom_redirect:
	
	JUMP _eeprom_write_handler;					// this routine will actually do the spi writes
	
_protect_eeprom.end:	
	

_unprotect_eeprom:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP unprotect_eeprom_redirect;		// if so jump to next state 

	ustat1 = DM(eeprom_wrsr + 2);
	BIT CLR ustat1 EE_STATUS_BP1 | EE_STATUS_BP0;	
	DM(eeprom_wrsr + 2) = ustat1;				// modify eeprom_wrsr data struct

	
	ustat1 = EE_CMD_UNPROTECT;
	DM(eeprom_command) = ustat1;				// for logging purposes
	DM(eeprom_addr) = m6;						// force to one
	DM(eeprom_data) = m6;						// force to one

	DM(eeprom_write_type) = m5;					// m5 = 0 , signify a status register write
	
	ustat1 = DM(eeprom_spi_service_state);		// signify that this state is done
	BIT SET ustat1 EE_SPI_INIT;
	DM(eeprom_spi_service_state) = ustat1;

unprotect_eeprom_redirect:
	
	JUMP _eeprom_write_handler;					// this routine will actually do the spi writes

_unprotect_eeprom.end:


//////////////////////////////////////////////////////////////////////////////////
//
//	_write_eedataKK
//
//	Notes:	
//		In writing data to the eeprom, there are three data widths supported 
//		in this library namely 8, 16 and 32.  Each handler will prepare the 
//		spi packet that will contain the write command, address and the data
//		then will branch to eeprom_write_handler which will actually execute
//		the actual write.  The user should be aware that when writing a 16 or 32 
//		bit word the address is modified in order to not conflict with the 
//		paging write issue.  In addition, this library does not check whether
//		it is out of the memory bounds. The memory location will wrap just like
//		a circular buffer if it exceeds the max address location (0x1FFF).
//
//		The user eeprom has an address space of 0x0000 to 0x1FFF.
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ eeprom_msg_log	
//							--> EE_CMD_WRITEKK  KK could be 8, 16, or 32
//							--> address
//							--> data
//							
//	Modified register:  	r14, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////	
_write_eedata8:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP _write_eedata8_handler;			// if so jump to next state

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	CALL get_eeprom_address_bytes;				// split address into 2 bytes

	DM(eeprom_write_data + 2) = r0;				// modify address
	DM(eeprom_write_data + 3) = r1;

	r15 = DM(eeprom_data);		
	r14 = 0xFF;
	r15 = r15 AND r14;							// byte mask
	
	DM(eeprom_write_data + 4) = r15;			// fill byte to spi packet location
	
	r15 = DM(eeprom_write_data);				// modify packet header to only send byte data
	r14 = 0xFF00;								// clear the spi transfer length first
	r15 = r15 AND r14;
	r14 = EE_SEND4;								// send 4 1 command, 16 bit address and 8 bit data
	r15 = r15 OR r14;
	DM(eeprom_write_data) = r15;				// update spi packet header 
	
	DM(eeprom_write_type) = m6;					// signify that this write is for data
	
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

_write_eedata8_handler:
	
	JUMP _eeprom_write_handler;					// this routine will actually do the spi writes

_write_eedata8.end:

_write_eedata16:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP _write_eedata16_handler;			// if so jump to next state

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	r15 = 0x1FFE;								// modify address and loose 1 lsb
	r4 = r4 AND r15;							// and avoid page issue on address wrap
	DM(eeprom_addr) = r4;						// update eeprom_addr var
	CALL get_eeprom_address_bytes;				// split address into 2 bytes
	DM(eeprom_write_data + 2) = r0;				
	DM(eeprom_write_data + 3) = r1;				

	r15 = DM(eeprom_data);		
	r4 = 0xFF;									// byte mask
	r14 = r15 AND r4;
	DM(eeprom_write_data + 5) = r14;			// get ls byte 
	r15 = LSHIFT r15 by -8;
	r15 = r15 AND r4;
	DM(eeprom_write_data + 4) = r15;			// get ms byte 
		
	r15 = DM(eeprom_write_data);				// modify packet header to only send byte data
	r14 = 0xFF00;								// clear the spi length first
	r15 = r15 AND r14;
	r14 = EE_SEND5;								// send 5, 1 command, 16 bit address and 2-8 bit data
	r15 = r15 OR r14;
	DM(eeprom_write_data) = r15;
	
	DM(eeprom_write_type) = m6;					// signify that this write is for data
	
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

_write_eedata16_handler:
	
	JUMP _eeprom_write_handler;					// this routine will actually do the spi writes

_write_eedata16.end:


_write_eedata32:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP _write_eedata32_handler;			// if so jump to next state

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	r15 = 0x1FFC;								// loose 2 lsbs for 32 bit aslignment
	r4 = r4 AND r15;							// and avoid page wrap issue in multiple data access
	DM(eeprom_addr) = r4;						// update eeprom_addr var
	CALL get_eeprom_address_bytes;				// split address into 2 bytes

	DM(eeprom_write_data + 2) = r0;				// modify address
	DM(eeprom_write_data + 3) = r1;		

	r15 = DM(eeprom_data);		
	r4 = 0xFF;									// byte mask
	r14 = r15 AND r4;
	DM(eeprom_write_data + 7) = r14;			// get ls byte 
	r15 = LSHIFT r15 by -8;
	r14 = r15 AND r4;
	DM(eeprom_write_data + 6) = r14;			// get low mid  byte 
	r15 = LSHIFT r15 by -8;
	r14 = r15 AND r4;
	DM(eeprom_write_data + 5) = r14;			// get high mid byte 
	r15 = LSHIFT r15 by -8;
	r15 = r15 AND r4;
	DM(eeprom_write_data + 4) = r15;			// get ms  byte 
	
	r15 = DM(eeprom_write_data);				// modify packet header to only send byte data
	r14 = 0xFF00;								// clear the spi length first
	r15 = r15 AND r14;
	r14 = EE_SEND7;								// send 7, 1 command, 16 bit address and 4 8 bit data
	r15 = r15 OR r14;
	DM(eeprom_write_data) = r15;
	
	DM(eeprom_write_type) = m6;					// signify that this write is for data
	
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

_write_eedata32_handler:
	
	JUMP _eeprom_write_handler;					// this routine will actually do the spi writes

_write_eedata32.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	_eeprom_write_handler
//
//	Notes:	
//		Issues three spi commands in order to properly modify the write status
//		register. It is essential to send a wren (write enable) command before 
//		sending a write status register command. After issuing the write status
//		register command, it is necessary to read the eeprom status register and
//		make sure that the write in progress is cleared before proceeding to other
//		eeprom commands.  Currently, all the write data functions and the protect
//		and unprotect commands branch into this handler.
//	
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			NONE
//							
//	Modified register:  	r4, r8 ,r12, r14, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////	
_eeprom_write_handler:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_WAIT;					// check if this state is done
	IF TF JUMP _eeprom_write_handler_wait;

_eeprom_write_handler_step1:
// step one is to issue a write enable command (wren)
	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_STEP1;				// check if this state is done
	IF TF JUMP _eeprom_write_handler_step2;

	r4 = eeprom_wren;							// write enable the eeprom
	CALL _spi_add_queue;						// this command needed in both 
												// status and data writes
	DM(eeprom_receive_buffer) = m6;				// re arm for next command

																								
	ustat1 = DM(eeprom_spi_service_state);
	BIT SET ustat1 EE_SPI_STEP1 | EE_SPI_WAIT;	// this state is done but will need
	DM(eeprom_spi_service_state) = ustat1;		// a spi transfer to be done next

	RTS;
_eeprom_write_handler_step2:
// step two is a write status register command (wrsr)

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_STEP2;				// check if this state is done
	IF TF JUMP _eeprom_write_handler_step3;

	r15 = DM(eeprom_write_type);				// check whether we are writing
	r15 = pass r15;								// the status reg or data memory
	IF EQ JUMP eeprom_send_write_status_register_command;
// if var eeprom_write_type = 0, write status reg but if = 1 write data
		
eeprom_send_write_data_command:
		
	r4 = eeprom_write_data;						// eeprom_write_data has be preformed
	CALL _spi_add_queue;						// dependent on data width (8,16,32)	

	DM(eeprom_receive_buffer) = m6;				// re arm for next command
		
	JUMP _eeprom_write_handler_step2_exit;
		
eeprom_send_write_status_register_command:	

	r4 = eeprom_wrsr;							// write status registers
	CALL _spi_add_queue;						
	
	DM(eeprom_receive_buffer) = m6;				// re arm for next command
	
_eeprom_write_handler_step2_exit:	
			
	ustat1 = DM(eeprom_spi_service_state);
	BIT SET ustat1 EE_SPI_STEP2 | EE_SPI_WAIT;	// this state is done but will need
	DM(eeprom_spi_service_state) = ustat1;		// a spi transfer to be done next

	RTS;
_eeprom_write_handler_step3:

// step three is to read the status register

	r4 = eeprom_rdsr;							// issue read status register command
	CALL _spi_add_queue;						
	
	DM(eeprom_receive_buffer) = m6;				// re arm for next command
			
	ustat1 = DM(eeprom_spi_service_state);
	BIT SET ustat1 EE_SPI_STEP3 | EE_SPI_WAIT;	// this state is done but will need
	DM(eeprom_spi_service_state) = ustat1;		// a spi transfer to be done next
	
	RTS;
_eeprom_write_handler_wait:
	
	r15 = DM(eeprom_receive_buffer);			// check for spi handshake
	r15 = pass r15;
	IF NE RTS;
	
	ustat1 = DM(eeprom_spi_service_state);
	BIT CLR ustat1 EE_SPI_WAIT;					// clear spi wait for next spi transfers
	DM(eeprom_spi_service_state) = ustat1;		// spi_wait state means a spi command is issued
	
	ustat1 = DM(eeprom_spi_service_state);
	
	BIT TST ustat1 EE_SPI_STEP3 ;				// check if we are in this state
	IF TF JUMP _eeprom_write_handler_wip_check; // if so jump here
	
	BIT TST ustat1 EE_SPI_STEP2 ;				// check if we are in this state
	IF TF JUMP _eeprom_write_handler_step3;		// go to next step
		
	BIT TST ustat1 EE_SPI_STEP1	;				// check if we are in this state
	IF TF JUMP _eeprom_write_handler_step2;		// go to next step

		
_eeprom_write_handler_wip_check:

	ustat1 = DM(eeprom_receive_buffer+2);			// check if still in write in progress
	BIT TST ustat1 EE_STATUS_WIP;				// if set issue another read statu reg
	IF TF JUMP 	_eeprom_write_handler_step3;

_eeprom_write_handler_exit:

// if it crosses here it means that the write process is done

	r4 = DM(eeprom_command);					// log command that issued a write status reg
	r8 = DM(eeprom_addr);
	r12 = DM(eeprom_data);
	
// note that for the write status reg version eeprom_addr and data = 1
	
	JUMP _exit_eeprom_command;					// standard exit routine

_eeprom_write_handler.end:
	
//////////////////////////////////////////////////////////////////////////////////
//
//	_read_eedataKK
//
//	Notes:	
//
//		This library allows the user to read data with different data widths
//		namely (8, 16, and 32 bit).  The three subroutines form the spi packet
//		to be sent to the eeprom accordingly.  This includes breaking the address
//		and data into bytes and zeroing out necessary lsbs to maintain data 
//		width alignment and avoid the page issue associated with multiple data access.
//		All of the subroutines branch into _eeprom_read_handler.
//
//		The user eeprom has an address space from 0x0000 to 0x1FFF.
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ eeprom_msg_log	
//							--> EE_CMD_READKK  KK could be 8, 16, or 32
//							--> address
//							--> data
//							
//	Modified register:  	r14, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////	
_read_eedata8:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP read_eedata8_handler;

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	CALL get_eeprom_address_bytes;				// split address into 2 bytes

	DM(eeprom_read_data + 2) = r0;				// modify address
	DM(eeprom_read_data + 3) = r1;

	r15 = DM(eeprom_read_data);					// modify packet header to only send byte data
	r14 = 0xFF00;								// clear the spi length first
	r15 = r15 AND r14;
	r14 = EE_SEND4;								// send 4, 1 command, 16 bit address and 8 bit data
	r15 = r15 OR r14;
	DM(eeprom_read_data) = r15;
	
	DM(eeprom_data_type) = m5;					// if 0, read 8 bit word to be read
		
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

read_eedata8_handler:
	
	JUMP _eeprom_read_handler;	

_read_eedata8.end:


_read_eedata16:


	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP read_eedata16_handler;

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	r15 = 0x1FFE;								// loose one lsb for 16 bit alignment
	r4 = r4 AND r15;							// and avoid page wrap issue in multiple data access
	DM(eeprom_addr) = r4;						// update eeprom_addr var
	CALL get_eeprom_address_bytes;				// split address into 2 bytes

	DM(eeprom_read_data + 2) = r0;				// modify address
	DM(eeprom_read_data + 3) = r1;				// to maintain 16 bit alignment

	r15 = DM(eeprom_read_data);					// modify spi packet header to only send 2 bytes data
	r14 = 0xFF00;								// clear the spi length first
	r15 = r15 AND r14;
	r14 = EE_SEND5;								// send 5 , 1 command, 16 bit address and 2 8 bit data
	r15 = r15 OR r14;
	DM(eeprom_read_data) = r15;
	
	DM(eeprom_data_type) = m6;					// if 1, read 16 bit word to be read
												// var will be used to construct 16 bit word from bytes
	
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

read_eedata16_handler:
	
	JUMP _eeprom_read_handler;
	
_read_eedata16.end:

_read_eedata32:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_INIT;					// check if this state is done
	IF TF JUMP read_eedata32_handler;

	CALL get_eeprom_parameters;					// get eeprom command, address and data
	
// form spi packet eeprom_write_data
	r4 = DM(eeprom_addr);
	r15 = 0x1FFC;								// loose two lsb for 32 bit alignment
	r4 = r4 AND r15;							// and avoid page wrap issue in multiple data access
	DM(eeprom_addr) = r4;						// update eeprom_addr var
	
	CALL get_eeprom_address_bytes;				// split address into 2 bytes

	DM(eeprom_read_data + 2) = r0;				// modify address
	DM(eeprom_read_data + 3) = r1;				// to maintain 32 bit alignment

	r15 = DM(eeprom_read_data);					// modify spi packet header to only send 4 bytes data
	r14 = 0xFF00;								// clear the spi length first
	r15 = r15 AND r14;
	r14 = EE_SEND7;								// send 7, 1 command, 16 bit address and 4-8 bit data
	r15 = r15 OR r14;
	DM(eeprom_read_data) = r15;
	
	DM(eeprom_data_type) = m7;					// if -1, read 32 bit word to be read
												// will be used to construct 32 bit word from bytes
		
	ustat1 = DM(eeprom_spi_service_state);	
	BIT SET ustat1 EE_SPI_INIT;					// signify that this state is done
	DM(eeprom_spi_service_state) = ustat1;

read_eedata32_handler:
	
	JUMP _eeprom_read_handler;

_read_eedata32.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	_eeprom_read_handler
//
//	Notes:	
//			
//		This subroutine is called by _read_dataKK routines.  This routine
//		issues the spi packet and waits upon completion.  At the end of 
//		reading data, this handler reforms the read data to a one word 
//		so as to keep the eeprom_msg_log alignment with a three word boundary.
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			@ eeprom_msg_log	
//							--> EE_CMD_WRITEKK  KK could be 8, 16, or 32
//							--> address
//							--> data
//							
//	Modified register:  	r4, r8, r12, r14, r15, ustat1
//
//////////////////////////////////////////////////////////////////////////////////	

_eeprom_read_handler:

	ustat1 = DM(eeprom_spi_service_state);
	BIT TST ustat1 EE_SPI_WAIT;					// check if this state is done
	IF TF JUMP eeprom_read_handler_wait;

eeprom_read_handler_step1:

	r4 = eeprom_read_data;						// eeprom_write_data has be preformed
	CALL _spi_add_queue;						// dependent on data width (8,16,32)	

	DM(eeprom_receive_buffer) = m6;				// re arm for next command
	
	ustat1 = DM(eeprom_spi_service_state);
	BIT SET ustat1 EE_SPI_STEP1 | EE_SPI_WAIT;	// set this state step and wait for 
	DM(eeprom_spi_service_state) = ustat1;

	RTS;
	
eeprom_read_handler_wait:

	r15 = DM(eeprom_receive_buffer);			// check for spi handshake
	r15 = pass r15;
	IF NE RTS;
	
	ustat1 = DM(eeprom_spi_service_state);
	BIT CLR ustat1 EE_SPI_WAIT;					// clear spi wait for next spi transfers
	DM(eeprom_spi_service_state) = ustat1;		// spi_wait state means a spi command is issued

// Now find out which type of data width was to be read from eeprom.
// This information is found in eeprom_data_type and the choices 	
// are if this variable
//							==	0 (8 bit ) 
//							==	1 (16 bit)
//							== -1 (32 bit)
// Utilize eq, gt, lt conditions to determine data width type
	
	r15 = DM(eeprom_data_type);
	r15 = pass r15;
	IF EQ JUMP eeprom_read_handler_form_data8;	// if equal to 0
	
	IF GT JUMP eeprom_read_handler_form_data16;	// if greater than 0, looking for 1	
	
	IF LT JUMP eeprom_read_handler_form_data32; // if less than 0, looking for -1

eeprom_read_handler_form_data8:

	r15 = DM(eeprom_receive_buffer + 4);		// the sole byte resides in this location
	DM(eeprom_data) = r15;						// save to eeprom_data variable
	JUMP eeprom_read_handler_exit;				
	
eeprom_read_handler_form_data16:

	r15 = DM(eeprom_receive_buffer + 4);		// the ms byte reside here
	r15 = LSHIFT r15 by 8;						// shift by 8 to give room for ls byte
	r14 = r15;
	r15 = DM(eeprom_receive_buffer + 5);		// get ls byte 
	r14 = r14 OR r15;							// combine by OR to have 16 bit data word
												
	DM(eeprom_data) = r14;						// update eeprom_data
	JUMP eeprom_read_handler_exit;

eeprom_read_handler_form_data32:	

	r15 = DM(eeprom_receive_buffer + 4);		// get ms byte	
	r15 = LSHIFT r15 by 8;						// shift by 8 to give room for next byte
	r14 = r15;									
	r15 = DM(eeprom_receive_buffer + 5);		// get high mid byte
	r14 = r14 OR r15;							// shift by 8 to give room for next byte
	r14 = LSHIFT r14 by 8;						// combine by OR
	r15 = DM(eeprom_receive_buffer + 6);		// get low mid byte
	r14 = r14 OR r15;							// shift by 8 to give room for next byte
	r14 = LSHIFT r14 by 8;						// combine by OR
	r15 = DM(eeprom_receive_buffer + 7);		// get ls byte
	r14 = r14 OR r15;							// combine by OR
	DM(eeprom_data) = r14;						// update eeprom data
	
eeprom_read_handler_exit:

	r4 = DM(eeprom_command);					// log command that issued a write status reg
	r8 = DM(eeprom_addr);
	r12 = DM(eeprom_data);						// this could be a 8, 16 or 32 bit word

	JUMP _exit_eeprom_command;					// standard exit routine
	
_eeprom_read_handler.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	get_eeprom_address_bytes
//
//	Notes:	Helper function for read and write processes. Divides
//			an address into two bytes.
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	r4 = 16 bit address to be splitted to 2 bytes
//
// 	Return value:			r0 = ms address byte
//							r1 = ls address byte
//							
//	Modified register:  	r0, r1, r4
//
//////////////////////////////////////////////////////////////////////////////////	
get_eeprom_address_bytes:	

	r0 = 0xFF;
	r1 = r4 and r0;						// take only 8 lsbs
	r4 = LSHIFT r4 by -8;				// right shift by 8 and 
	r0 = r4 and r0;						// mask 8 lsbs 
	RTS;				

get_eeprom_address_bytes.end:

//////////////////////////////////////////////////////////////////////////////////
//
//	get_eeprom_parameters
//
//	Notes:	Helper function for read and write processes. Gets eeprom command
//			address and data.  Information is drawn from eeprom queue.
//		
//	Written by Danville Signal Processing
//
//	Date:					10 June 05
//
//	Calling parameters: 	NONE
//
// 	Return value:			DM(eeprom_command)
//							DM(eeprom_addr)
//							DM(eeprom_data)
//							
//	Modified register:  	b1, i1, l1, r15
//
//////////////////////////////////////////////////////////////////////////////////	
get_eeprom_parameters:

	b1 = eeprom_queue;							// grab the command type from queue
	i1 = DM(eeprom_queue_head_ptr);
	l1 = EE_QUEUE_SIZE;
	
	r15 = DM(i1,m6);
	DM(eeprom_command) = r15;					// get three word parameter
	r15 = DM(i1,m6);							// namely eeprom command, address
	DM(eeprom_addr) = r15;						// and data
	r15 = DM(i1,m6);
	DM(eeprom_data) = r15;		
	l1 = m5;
// do not update tail pointer, we are just merely grabbing information

	RTS;
get_eeprom_parameters.end:

	
	
	
	
	

